I'm getting this error:
Type 'Observable<Country[]>' is not assignable to type 'Observable'. Type 'Country[]' is missing the following properties from type 'Country': name, tld, alpha2Code, alpha3Code, and 20 more.ts(2322
I think it's because the endpoint im reaching serves back an array with an object inside of it. Here's an example.
https://restcountries.com/v3.1/name/peru
This is the code I can't get to work. It refuses to compile and gives me the error I posted above.
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 looks like this:
getCountryByName(name: string) {
return this.http
.get<Country[]>(`${this.api}/name/${name}`)
}
How do I get the "this.country$" variable/observable/subject (idk what it is technically), to hold the data thats inside the object thats inside of the array that's being returned by the HTTP request?
I thought I could map the values out of the array, but this doesn't work either:
ngOnInit(): void {
this.activatedRoute.params.subscribe((params) => {
let countryName = params['country'];
this.country$ = this.apiService.getCountryByName(countryName).pipe(map(([info])=>return info)
});
};
}
When I do that, I don't get the error but this template:
<div *ngIf="country$ | async as country">
<h1>{{country$}}</h1>
</div>
renders
[object Object]
...like the h1 on the page literally just says "[object Object]"
What am I doing wrong? What combination of operators do I need to use to convert the 'Observable<Country[]>' into just 'Observable<Country' so I can render it inside an 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>
This is the interface in case it's relevant to the answer:
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;
// nativeName: string;
// numericCode: string;
// regionalBlocs: RegionalBloc[];
}
CodePudding user response:
Looks like you have a typing issue in your getCountryByName
method. Instead of .get<Country[]>
, it should be .get<Country>
:
getCountryByName(name: string) {
return this.http
.get<Country>(`${this.api}/name/${name}`)
}
CodePudding user response:
The RestCountries API returns the response with an array type. You can achieve with extract the first element of the array via map
rxjs.
getCountryByName(name: string): Observable<Country> {
return this.http
.get<Country[]>(`${this.api}/name/${name}`)
.pipe(map((x) => x[0]));
}
The way you extract the properties from the country$
Observable is incorrect. You should look for an async
pipe as what you have achieved 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>