QKuba
QKuba

Reputation: 35

How to iterate through JSON array in angular

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>

Upvotes: 0

Views: 2520

Answers (1)

Barremian
Barremian

Reputation: 31125

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.

Upvotes: 1

Related Questions