kronus
kronus

Reputation: 912

Angular 6 ngFor select object on a nested JSON

I am have a hard time trying to do an ngFor on nested JSON. I have read that ngFor is supposed to be for arrays only, but there are so many APIs that pump out nested JSON, that I figure that has to be a way.

The following is an example of the category JSON that I am receiving - I am simplifying what it could be:

{
  "Categories": {
    "candles": {
      "name": "Candle"
    },
    "oils": {
      "name": "Oil"
    },
    "chocolates": {
      "name": "Chocolates"
    },
    "toys": {
      "name": "Toys"
    }
  }
}

The following is an example of the http get:

  this.http.get(this.jsonUriNestObj).subscribe(resultObj => {
  this.categoryObj = resultObj["Categories"];
  console.log(
    "resultObj['Categories']: ",
    JSON.stringify(resultObj["Categories"])
  );

This would be an example of what comes back in the console:

resultObj['Categories']:  {"candles":{"name":"Candle"},"oils":{"name":"Oil"},"chocolates":{"name":"Chocolates"},"toys":{"name":"Toys"}}

The following is what is currently not displaying any options in the select, but at the same time, zero errors and zero warnings:

<select id="categories" class="form-control">
  <option value="">Please select an item</option>
  <option
    *ngFor="let item of this.categoryObj.name; let i = index"
    value="{{ i }}"
    >{{ item }}</option
  >
</select>

I have tried this.categoryObj[i], this.categoryObj[i]['name'], etc...

How do I ngFor a nested JSON - hopefully, you can offer a dynamic solution.

As usual, thanks in advance and happy new year to you and yours

Upvotes: 2

Views: 2621

Answers (3)

Rahul
Rahul

Reputation: 2128

You can use keyValue pipe to iterate objects - I think this pipe is available from angular 6.1

Try something like this

<select id="categories" class="form-control">
  <option value="">Please select an item</option>
  <option
    *ngFor="let item of this.categoryObj | keyvalue; let i = index"
    value="{{ item.key }}"
    >{{ item.value.name }}</option
  >
</select>

I think this might help you - but make sure this pipe seems to be impure

For more info check this - Happy new year and happy coding :)

Upvotes: 1

Prashant Pimpale
Prashant Pimpale

Reputation: 10697

Declare one variable to hold the revised JSON list:

list : any[] = [];

Just replace your get request with this:

this.http.get(this.jsonUriNestObj).subscribe(resultObj => {
    this.categoryObj = resultObj["Categories"];
    Object.keys(this.categoryObj).forEach(key => {
       this.list.push(this.categoryObj[key])
    })
});

HTML:

<select id="categories" class="form-control">
  <option value="">Please select an item</option>
  <option *ngFor="let item of list; let i = index" [value]="i">
      {{ item.name }}
  </option>
</select>

FORKED STACKBLITZ

Upvotes: 0

Just code
Just code

Reputation: 13801

You are iterating over the object not array, array can be iterated easily.

You can use pipe to transform your objects to array or you can change your json object to array.

You need one new variable which can iterate easily and you can use it later, like this

 name = 'Angular';
  categoryObj =  {"candles":{"name":"Candle"},"oils":{"name":"Oil"},"chocolates":{"name":"Chocolates"},"toys":{"name":"Toys"}}
  outputData: any;

  constructor(){
    this.outputData = Object.keys(this.categoryObj).reduce((prev,curr)=>{          
      prev.push(this.categoryObj[curr].name);
      return prev;
    },[])
  }

and in your view

<select id="categories" class="form-control">
  <option value="">Please select an item</option>
  <option
    *ngFor="let item of this.outputData; let i = index"
    value="{{ i }}"
    >{{ item }}</option
  >
</select>    

EDIT: As you want to iterate through object inside array, you can use

 this.outputData = Object.keys(this.categoryObj).reduce((prev, curr) => {     
      prev.push(this.categoryObj[curr]);
      return prev;
    }, [])

this will give you array of objects

0: Object
name: "Candle"

1: Object
name: "Oil"

and you can bind it like this

<select id="categories" class="form-control">
  <option value="">Please select an item</option>
  <option
    *ngFor="let item of this.outputData; let i = index"
    value="{{ i }}"
    >{{ item.name }}</option
  >
</select>

Demo

Upvotes: 1

Related Questions