Reputation: 912
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
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
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>
Upvotes: 0
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>
Upvotes: 1