What is the best way to transform an Observable array containing objects into an Observable that emits the data contained within those objects?

Encountering an error:

Error: Type 'Observable<Country[]>' is not assignable to type 'Observable'. Type 'Country[]' is missing properties like name, tld, alpha2Code, alpha3Code and more.ts(2322


The issue might be due to the endpoint returning an array with objects. Here's an example.


Here's the code that's failing to compile and producing the above error.

export class DetailsComponent implements OnInit {
  country$!: Observable<Country>
  countryBorders$!: Observable<Country[]>

  constructor(private apiService: ApiService, private activatedRoute: ActivatedRoute){}

  ngOnInit(): void {
    this.activatedRoute.params.subscribe((params) => {
      let countryName = params['country'];
      this.country$ = this.apiService.getCountryByName(countryName)
    });
    };
  }

The getCountryByName() method implementation:

  getCountryByName(name: string) {
    return this.http
      .get<Country[]>(`${this.api}/name/${name}`)
  }

How can I make the 'this.country$' variable hold the object data from the array returned by the HTTP request?

I tried mapping the values from the array but it did not work as expected:

  ngOnInit(): void {
    this.activatedRoute.params.subscribe((params) => {
      let countryName = params['country'];
      this.country$ = this.apiService.getCountryByName(countryName).pipe(map(([info])=>return info)
    });
    };
  }

After making these changes, instead of the error, the template renders:

<div *ngIf="country$ | async as country">
  <h1>{{country$}}</h1>
</div>

...and the h1 displays "[object Object]".

What am I doing wrong? What operators should I use to convert 'Observable<Country[]>' to 'Observable<Country' for rendering in the html template like this?

  <div>
    <p><strong>Native Name: </strong>{{ country$.name.nativeName }}</p> 
    <p><strong>Population: </strong>{{ country$.population | number : '0.0' }}</p> 
    <p><strong>Region: </strong>{{ country$.region }}</p> 
    <p><strong>Sub Region: </strong>{{ country$.subregion }}</p> 
    <p><strong>Capital: </strong>{{ country$.capital }}</p></div>
    <div> 
      <p><strong>Top Level Domain: </strong>{{ country$.tld }}</p> 
      <p><strong>Currencies: </strong>{{ country$.currencies }}</p> 
      <p><strong>Languages: </strong>{{ country$.languages }}</p>
   </div>
</div>

If relevant, here's the interface definition:

export interface Country {
  name: Name; //---
  tld: string[]; //---
  cca2: string;
  ccn3: string;
  cca3: string;
  cioc: string;
  independant: Boolean
  status: string;
  unMember: Boolean;
  currencies: Currency[]; //---
  idd: Idd;
  capital: string[]; //---
  altSpellings: string[];
  region: string;
  subregion: string; //---
  languages: any; //---
  translations: any;
  latlng: number[];
  landlocked: Boolean;
  borders: string[]; //---
  area: number;
  demonyms: any;
  flag: string;
  maps: Maps;
  population: number; //---
  gini: any;
  fifa: string;
  car: any;
  timezones: string[];
  continents: string[];
  flags: Flags;
  coatOfArms: COA;
  startOfWeek: string;
  capitalInfo: Capital;
  postalCode: Postal;
}

Answer №1

It appears that there is a small error in the getCountryByName function related to typing. Instead of using .get<Country[]>, it should be changed to .get<Country>:

getCountryByName(name: string) {
  return this.http
    .get<Country>(`${this.api}/name/${name}`)
}

Answer №2

The RestCountries API provides a response in array format. To extract the first element of the array using map from rxjs.

getCountry(name: string): Observable<Country> {
  return this.http
    .get<Country[]>(`${this.api}/name/${name}`)
    .pipe(map((data) => data[0]));
}

Your method of extracting properties from the country$ Observable is incorrect. Make sure to use an async pipe like demonstrated in the question.

<div *ngIf="country$ | async as country">
  <div>
    <p><strong>Native Name: </strong>{{ country.name.nativeName | json }}</p>
    <p>
      <strong>Population: </strong>{{ country.population | number: '0.0' }}
    </p>
    <p><strong>Region: </strong>{{ country.region }}</p>
    <p><strong>Sub Region: </strong>{{ country.subregion }}</p>
    <p><strong>Capital: </strong>{{ country.capital }}</p>
  </div>
  <div>
    <p><strong>Top Level Domain: </strong>{{ country.tld }}</p>
    <p><strong>Currencies: </strong>{{ country.currencies }}</p>
    <p><strong>Languages: </strong>{{ country.languages }}</p>
  </div>
</div>

Check out the Demo on StackBlitz

Answer №3

The correct structure was as follows:

export class DetailsComponent implements OnInit {
  country$!: Observable<Country>
  countryBorders$!: Observable<Country[]>

  constructor(private apiService: ApiService, private activatedRoute: ActivatedRoute){}

  ngOnInit(): void {
    this.activatedRoute.params.subscribe((params) => {
      let countryName = params['country'];
      this.country$ = this.apiService.getCountryByName(countryName).pipe(map(([info])=>{return info}))
    });
    };
  }

I followed the right steps. However, in the template, make sure to use:

<div *ngIf="country$ | async as country">
  <h1>{{country.name.common}}</h1>
</div>

NOT

<div *ngIf="country$ | async as country">
  <h1>{{country$.name.common}}</h1>
</div>

Silly mistake on my part

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When exporting data to Excel, the date is automatically adjusting based on the timezone. Is there a way to prevent this from happening

Whenever I attempt to export data to excel in angular, I encounter an issue with time zones. The date in the database is set in timezone 'x', while I am exporting data from timezone 'y'. As a result, the exported data in Excel displays ...

Issue with Angular uploading a file and sending it as a POST request causing errors

I am currently working on an HTML form that allows users to upload files from the front-end to the back-end and perform various operations on them: <button mat-raised-button color="primary" type="button" style='margin-right:20px ...

Can jQuery help me identify which <input type='image> was clicked within a form containing several submit images?

Consider this hypothetical scenario: <form> <input type="text" name="some_name" value="val" id="some_name"> <input type="image" value="action" alt="Add To Cart" name="add" src="/images/submit.gif"> <input type="image" value="act ...

New update in Next.js version 13.4 brings a modification to routing system

I'm currently working with Next.js 13.4 and an app directory. I'm trying to implement a centrally located loader that will show whenever there is a route change anywhere within the app. Since routes/navigation don't have event listeners, I&a ...

Tips for positioning a picklist field dropdown on top of a lightning card in Lightning Web Components

Attempting to resolve an issue with CSS, I have tried adding the following code: .table-responsive, .dataTables_scrollBody { overflow: visible !important; } However, the solution did not work as expected. Interestingly, when applying a dropdown pickli ...

Is it the browser's responsibility to convert ES6 to ES5 internally?

Given the support for ES6 in modern browsers, do they internally convert ES6 to ES5 before executing the code? Or can they process ES6 natively using a C++ engine? If they are able to run ES6 directly, how do they guarantee that executing ES6 code produce ...

Node.js making an API request

I am encountering an issue with the following code snippet: const req = require("request"); const apiReq = req("http://example.com/car/items.json", (err, res, body) => { if (!err && res.statusCode === 200) { return JSON.parse(body); } } ...

How do I successfully pass a service instance to a component located within an Angular library?

In my component library, I am creating several shared components that serve different functions. However, there is a new requirement that involves a more complex task which requires a service from the parent application to be used within one of the librar ...

What is the best way to use checkboxes to highlight table rows in Jquery Mobile?

I have a Jquery Mobile site with a table. Each table row contains checkboxes in the first cell. I am trying to achieve the following: a) Highlight a row when the user clicks on it b) Highlight a row when the user checks the checkbox I have made progr ...

How can I use JavaScript or JQuery to retrieve the HTML content as a string from a specific URL?

How can I extract the URL of a link from a webpage and add it to my code without an ID for that specific link? Is there a way to search based on the content within the <a> tag? ...

What is the best way to have a button activate a file input when onChange in a React application?

Having an input field of file type that doesn't allow changing the value attribute and looks unattractive, I replaced it with a button. Now, I need the button to trigger the input file upon clicking. How can this be achieved in React? Edit: The butto ...

Having trouble with importing SendInBlue into my NodeJS application?

Currently in the process of updating my Node app to utilize ES6 import modules over requiring files. Encountering difficulties while trying to integrate this change with SendInBlue for email functionality, resulting in the following error message: TypeEr ...

Storing string variables within an array and subsequently evaluating the similarity of each variable's value with those stored within the array

I am currently working on an Angular page which consists of input fields where I capture and store values in variables within the .ts file. The entered values are subject to change, so hard-coding them is not feasible. The variables that I use for storing ...

What is the URL I need to visit in my browser to monitor updates while running npm?

I am interested in utilizing npm to monitor any changes made in my project and immediately view them in my browser. Essentially, I have been implementing npm using this modified code snippet from this source, which allows me to run the command npm run buil ...

What is the best way to create an assertion function for validating a discriminated union type in my code?

I have a union type with discriminated properties: type Status = { tag: "Active", /* other props */ } | { tag: "Inactive", /* other props */ } Currently, I need to execute certain code only when in a specific state: // At some po ...

The @HostListener in Angular2 does not function correctly within a component that is inherited from another component

My Angular2-based client-side application has a base class: abstract class BaseClass { @HostListener('window:beforeunload') beforeUnloadHandler() { console.log('bla'); } } and two similar derived classes: @Component({ ...

What steps should I take to resolve the missing properties error stating '`ReactElement<any, any>` is lacking `isOpen` and `toggle` properties that are required by type `SidebarInterface`?

I've encountered an issue with two React components that appear to be configured similarly. The first component is a Navbar: type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> & { ...

Encountered an issue with reading the property 'drop' from an undefined source during a straightforward migration

I recently started using the migrate-mongo library and encountered an issue during a simple migration process to create a view. Despite success in migrating up, I faced an error when attempting to migrate down. ERROR: Could not migrate down 20220620114132 ...

Issue encountered when submitting form: Error identified as "Unexpected string expression without template curly in string"

As a novice in React.js, I am facing an issue where setState is not functioning properly when submitting a form. Any suggestions on how to resolve this problem? > class Home extends Component{ constructor(props){ > super(props) > ...

"The custom input component still displays a required error message even after all fields have been filled

After implementing the ControlValueAccessor interface to create a custom input component and setting the required property to true for form validation, I am facing an issue where the input field still shows a "required" error even when it is filled. The mo ...