0

In my angular application I am using an api to fetch data about a selected country.

I am not able to make my application display the name property from the languages section in the response data, which looks like this:

[{
    "name": "Colombia",
    "topLevelDomain": [".co"],
    "alpha2Code": "CO",
    "alpha3Code": "COL",
    "callingCodes": ["57"],
    "capital": "Bogotá",
    "altSpellings": ["CO", "Republic of Colombia", "República de Colombia"],
    "region": "Americas",
    "subregion": "South America",
    "population": 48759958,
    "latlng": [4.0, -72.0],
    "demonym": "Colombian",
    "area": 1141748.0,
    "gini": 55.9,
    "timezones": ["UTC-05:00"],
    "borders": ["BRA", "ECU", "PAN", "PER", "VEN"],
    "nativeName": "Colombia",
    "numericCode": "170",
    "currencies": [{
        "code": "COP",
        "name": "Colombian peso",
        "symbol": "$"
    }],
    "languages": [{
        "iso639_1": "es",
        "iso639_2": "spa",
        "name": "Spanish",
        "nativeName": "Español"
    }],
    "translations": {
        "de": "Kolumbien",
        "es": "Colombia",
        "fr": "Colombie",
        "ja": "コロンビア",
        "it": "Colombia",
        "br": "Colômbia",
        "pt": "Colômbia"
    },
    "flag": "https://restcountries.eu/data/col.svg",
    "regionalBlocs": [{
        "acronym": "PA",
        "name": "Pacific Alliance",
        "otherAcronyms": [],
        "otherNames": ["Alianza del Pacífico"]
    }, {
        "acronym": "USAN",
        "name": "Union of South American Nations",
        "otherAcronyms": ["UNASUR", "UNASUL", "UZAN"],
        "otherNames": ["Unión de Naciones Suramericanas", "União de Nações Sul-Americanas", "Unie van Zuid-Amerikaanse Naties", "South American Union"]
    }],
    "cioc": "COL"
}]

I have tried using pipes, nested *ngFor Loops but no luck in displaying the name of the language. Any suggestions?

In my template I am using the following HTML and interpolation to display the name of country object: How to use a similar approach to access the name property within the languages of the response data?

             <div>
                <label>Country Capital:</label>
                <p>{{ country.capital }} </p>
            </div>

My application consists of 3 Modules, 1 parent (CountryComponent) and two children components, (CountryListComponent) and (CountryDetailComponent). The data is sent from the List component to the Detail component using eventEmmiter. I am using the following model for the Country type:

 export interface Country {

      name: string;
topLevelDomain?: string[];
alpha2Code?: string;
alpha3Code?: string;
callingCodes?: string[];
capital?: string;
altSpellings?: string[];
region?: string;
subregion?: string;
population?: number;
latlng?: number[];
demonym?: string;
area?: number;
gini?: number;
timezones?: string[];
borders?: string[];
nativeName?: string;
numericCode?: string;
currencies?: Currency[];
languages?: Language[];
translations?: Translation;
flag?: string;
regionalBlocs?: Regional[];
cioc?: string;

}

In my List Component i use the following to fetch data using the service class and initialise the countries array of type Country, and use eventEmmiter to emit the country object to the Detail component:

 public countries: Country[];
  getCountries(){
    this.countryService
      .getCountries()
      .subscribe((data: any) => {
        this.countries = data;
      },
      error => {console.log('error loading')});
  }
  @Output() selectedCountry = new EventEmitter<Country>();

List Component Template:

<li class="list-group-item" 
            highlightDirective 
            style="cursor: pointer;
                text-align: center;
                font-family:'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;"
            *ngFor="let country of countries | searchFilter: searchText : 'name'" (click)="onCountrySelected(country)">
            {{ country.name }}
        </li>

In Detail component i receive the event:

@Input() country: Country;

And in Detail Template i am trying to display it:

    <h2> {{ country.name }} </h2>
        <br>
        <div class="row" #countrySelected>
            <div class="col-sm">
                <label>Country Capital:</label>
                <p>{{ country.capital }} </p>
                <p>{{ country.languages.name }}</p>
            </div>
            <div>

I use the eventEmmiter to send the country object from List component to the Detail component using the parent component, the parent template is as follows:

<div class="row"
style="padding-left: 20px;
        padding-right: 20px;">
    <div class="col-xs-5">
        <app-country-list (selectedCountry)="childEventClicked($event)"></app-country-list>
    </div>
    <div class="col-xs-7">
        <app-country-detail [country]="(selectedCountryEvent)"></app-country-detail>
    </div>
</div>
6
  • Try storing the JSON in a variable then parsing it. The you should be able to loop through it. Commented Apr 26, 2020 at 17:33
  • 1
    Notice that in interface Country the property languages is string[]. It should be any[] AFAIK Commented Apr 26, 2020 at 19:33
  • Thanks @Benny, i tried all of this, i have also assigned a custom type and created separate interfaces for these array of objects like languages. Nothing works... Commented Apr 26, 2020 at 19:41
  • 1
    Upload to StackBlitz Commented Apr 26, 2020 at 20:04
  • @Benny, Thanks for the response, here is the link to the project: stackblitz.com/edit/angular-fe7nzr Commented Apr 26, 2020 at 21:02

1 Answer 1

1

Given that each object is contained in an array, I assume that each property could contain more than one object as values. You could try the following.

I am assigning the respone from the API to a variable called countries.

Controller

countries = [];

getData() {
  this.apiService.getCountries().subscribe(
    response => { this.countries = response; },
    error => { // handle error }
  );
}

Template

<div *ngFor="let country of countries">
  <label>Country Capital:</label>
  <p>{{ country.capital }} </p>
  <label>Languages:</label>
  <p *ngFor="let language of country.languages">{{ language.name }}</p>
  <label>Currencies:</label>
  <p *ngFor="let currency of country.currencies">{{ currency.name }}</p>
</div>

Update

There is an issue with the interface definition. The languages property is defined as an array of type string whereas it's a custom object. You could define a separate interface for each type of object. Try the following

export interface Country {
  name: string;
  topLevelDomain?: string[];
  alpha2Code?: string;
  languages?: Language[];
  currencies?: Currency[];
  translations?: Translate[];
  regionalBlocs?: RegionalBloc[];
  .
  .
  .
}

export interface Language {
  iso639_1:? string;
  iso639_2:? string;
  name:? string;
  nativeName:? string;
}

And the same goes for other properties currencies, translations and regionalBlocs. Each need their own interface definitions similar to the one shown here for languages.

Sign up to request clarification or add additional context in comments.

8 Comments

I have already tried that approach and keep getting this error: "Identifier 'name' is not defined. 'string' does not contain such a member"
Could you please should what you've tried already that went wrong? And also show how you are assigning the values in the controller.
I have updated the question to give slightly better understanding.
I've updated the answer with regards to the interface definition.
Hmm understand where i made the mistake here. I have updated the code but now i cannot access any property but the name property.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.