Angular 8 Nested Object Interpolation - html

This is my version of Angular CLI:
Angular CLI: 7.3.9
Node: 12.2.0
OS: win32 x64
Angular: 8.0.2
While making an Angular 8 application, I am trying to use nested FormGroups which correspond to the following object:
const Boilerplate: any = {
1: {
desc: "section1",
content: {
1: "question 1.a:",
2: "question 1.b:",
3: "question 1.c"
}
},
2: {
desc: "section2",
content: {
4: "question 2.a:",
5: "question 2.b:",
6: "question 2.c",
7: "question 2.d"
}
}
}
There is an inner FormGroup of FormControls for section 1 and section 2, and an outer FormGroup holding the two inner formgroups. This is defined in the component.ts.
In the component.html, I am trying to iterate through the outer FormGroup's inner FormGroups, and print the inner FormControls. This is the code I have so far:
<form [formGroup]="sectionGroup">
<div *ngIf="boilerplate">
<div *ngFor="let section of boilerplate | keyvalue">
{{ boilerplate[section.key].desc }}
<div formGroupName="{{section.key}}">
<div *ngFor="let question of boilerplate[{{section.key}}]">
<-- things -->
</div>
</div>
</div>
</div>
The line <div *ngFor="let question of boilerplate[{{section.key}}]"> fails with an error message of:
Unexpected token {, expected identifier, keyword, or string
I have tried the following solutions, none of which have worked for me:
<div *ngFor="let question of {{boilerplate}}.{{section.key}}">
<div *ngFor="let question of {{boilerplate[section.key]}}">
<div *ngFor="let question of {{boilerplate[{{section.key}}]}}">
<td *ngFor="let question of Section">{{boilerplate[[section.key]]}}</td>
I have tried a variety of other {} and [] combinations and orders, and I realize now that nested interpolation is non-parsable.
Does anyone have a suggestion of how I can achieve this? I am using nested FormGroups because it is possible I will have additional layers of sections in the future. The format of the Boilerplate object can be changed if it would make the problem solvable (because I defined it, myself).
EDIT
The following was the solution that resolved this issue:
<div *ngFor="let question of boilerplate[section.key].content | keyvalue">
{{question.value}}
</div>

I try like below,
<div [formGroup]="formGroup">
<div *ngIf="boilerplate">
<div *ngFor="let section of boilerplate | keyvalue">
{{ boilerplate[section.key].desc }}
<div>
<div *ngFor="let question of boilerplate[section.key].content | keyvalue">
{{ question | json }}
</div>
</div>
</div>
Output is like below,
section1
{ "key": "1", "value": "question 1.a:" }
{ "key": "2", "value": "question 1.b:" }
{ "key": "3", "value": "question 1.c" }
section2
{ "key": "4", "value": "question 2.a:" }
{ "key": "5", "value": "question 2.b:" }
{ "key": "6", "value": "question 2.c" }
{ "key": "7", "value": "question 2.d" }

You need to use a keyValue filter pipe then you could just have the following syntax, this will let you use ngFor* to iterate though objects rather than arrays.
<div *ngFor="let question of boilerplate | keyValue">
{{ question.key }} - {{ question.value }}
</div>
You can then do the same for the nested objects inside until you have the correct data displayed. This is not supported in all versions of Angular, but definitely fine in 8.
Where you have Objects with the key as a number, I would look to manipulate that into an array which would help you keep this a little more simple. Allowing you to use traditional *ngFor

The answer from schoolcoder is great, I just would like to post another example for people in the future with the same problem.
I have an object Block that holds a list of Transactions and I want to show it on my page using two *ngFor's
Block model class:
export class Block {
hash: string;
previousBlockHash: string;
transactions: Transaction[]; <<<<<<<<<<<
merkleRoot: string;
tries: number;
timestamp: number;
}
Transaction model class
export class Transaction {
hash: string;
text: string;
senderHash: string;
signature: string;
timestamp: number;
}
How I show it on my page:
Blocks:
<div class="container">
<ul class="list-group">
<li class="list-group-item" *ngFor="let block of blocks | keyvalue">
Hash: {{blocks[block.key].hash}}<br>
Previous block hash: {{blocks[block.key].previousBlockHash}}<br>
Merkle root: {{blocks[block.key].merkleRoot}}<br>
Tries: {{blocks[block.key].tries}}<br>
Timestamp: {{blocks[block.key].timestamp}}<br>
Transactions in this block:
<ul class="list-group">
<li class="list-group-item" *ngFor="let transaction of blocks[block.key].transactions">
{{[block.key]}}<br>
Hash: {{transaction.hash}}<br>
Text: {{transaction.text}}<br>
SenderHash: {{transaction.senderHash}}<br>
Signature: {{transaction.signature}}<br>
Timestamp: {{transaction.timestamp}}
</li>
</ul>
</li>
</ul>
</div>

Related

How present JSON List in Angular HTML with *ngFor

I get a result in the JSON Format like these sample from a webservice.
How can i iterate over this items to prensent the objects
HTML Code - not working
<div *ngFor="let item of List">
{{item.Code}}
</div>
JSON Sample
"List": {
"0": {
"Code": "A"
},
"1": {
"Code": "B"
},
"2": {
"Code": "C",
}
}
unfortunally the webservice does not provide this as an Array [] of objects
I want to see the list of all items für the Key "Code"
You can use KeyValuePipe like here.
So the your code would be something like this:
<div *ngFor="let item of List | keyvalue">
{{item.value.Code}}
</div>
As it was not working with
<div *ngFor="let item of List | keyvalue">
{{item.value.Code}}
</div>
Typescript was throwing an error because {{item.value.Code}} was not known.
I did some additional research and found the following solution
<div *ngFor='let key of objectKeys(List)'>
{{List[key].Code}}
</div>
in the typescript class corresponding to the html file you have to add
objectKeys = Object.keys;

How to bind a single element from a model object in angular in a template

Can someone give me a clue, how to bind a variable value from a .model created?
I have used ng for in a div, then I can interpolate values from a .model.ts using:
ngFor let list of lists
then i {{name.list}}
But in other div, I just can show a dynamic name of a .model.ts, like name.list.
How can I do this?
Thanks
If you have in your component some data like:
usersList = [
{ name: "Michael", id: 1 },
{ name: "Linda", id: 2 }
];
In your template html you should do something like this:
<h2>List of users</h2>
<ul *ngIf="userList.length">
<li *ngFor="let user of userList">
Hello {{user.name}} (id: {{user.id}})
</li>
</ul>
<div *ngIf="!userList.length">No users</div>

How i can do a *ngFor in a array of objects that i don't know the name property?

I have this array called dadosRelatorio that i need to iterate in my template, this array i get in a http request:
[{"id": 1,
"name": "a",
"class":[{
"Inglês":[{
"id": 1,
"code": "teste"
},
{
"id": 2,
"code": "teste 2"
}],
"Espanhol":[{
"id": 1,
"code": "a"
}]
}]
}]
How i can iterate the objects inside class if they have different names property? Sometimes the name can be "Inglês" and sometimes can be "Espanhol" and other names...
When i know the name of the property i do this way:
<div *ngFor="let aluno of dadosRelatorio" class="div-aluno">
<span>Aluno: {{ aluno.name }}</span>
<div *ngFor="let classe of aluno.class">
<div *ngFor="let idioma of classe. ???>
</div>
</div>
</div>
But how i can iterate the object inside class?
You may iterate using the keyvalue pipe as shown below:
<div *ngFor="let aluno of dadosRelatorio" class="div-aluno">
<span>Aluno: {{ aluno.name }}</span>
<div *ngFor="let classe of aluno.class | keyvalue">
<div> {{classe.key}}</div>
<div *ngFor="let type of classe.value | keyvalue">
{{type.key}}
<div *ngFor="let data of type.value | keyvalue">
{{data.value.id }}
{{data.value.code }}
</div>
</div>
</div>
</div>
You can enumerate an object keys using Object.keys.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys.
edit: You can also use the keyvalue pipe as describe in the official documentation: https://angular.io/api/common/KeyValuePipe
I thought there was a ngForIn directive as well, but I cant find the doc.

Access nested json object angular 6

I'm trying to access the nested data from the HTML template, but I get undefined or I get nothing as result (empty page with no class list or student list).
The HTML template:
<div class="container">
<label *ngFor="let class of listClass | keyvalue">
<span> {{class.value.name}} </span>
</label>
<div>
<label *ngFor="let student of class.students | keyvalue">
<span>{{student.value.fullName}} </span>
</label>
</div>
</div>
This is the fonction that gets the list of class and the students in it:
getListClasseStudent(){
this.classService.getStudents().subscribe((data) => {
this.listClass = data;
});
}
The nested data:
class:
0:{
code: "Math01"
teacher:
0: {id: 17551, name "Jack"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
1:{
code: "English01"
teacher:
0: {id: 2, name "Nicolas"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
I want to access to the list of student of each class, is there any efficient way to do it? thanks in advance.
<div class="container">
<div *ngFor="let c of listClass ">
<label >
<span> {{c.code}} </span>
</label>
<div>
<label *ngFor="let student of c.students ">
<span>{{student.fullName}} </span>
</label>
</div>
</div>
Try this (example without your pipe)
A 'Class' object don't have a attribute 'value.name' (probably gonna be injected by your pipe '| keyvalue' ).
Second *ngFor need t be inside of first, because he need's to iterate a students array, inside each class.
I hope this helps.
create a pipe like below
import { Pipe, PipeTransform } from "#angular/core";
#Pipe({ name: 'ObjNgFor', pure: false })
export class ObjNgFor implements PipeTransform {
transform(value: Object): Array<string> { return Object.keys(value); }
}
import the above pipe in app.module.ts and use pipe in the html page like below
<div *ngFor="let key of questions | ObjNgFor" class="row">
{{ questions[key].name}}
<div *ngFor="let r of questions[key].sub_sections | ObjNgFor ; let indx=index"
class="card-body">
{{ questions[key].sub_sections[r].name }}"
</div>
This example should work

angular 2 ngFor Cannot read property of undefined

I have a nested object with data that I am trying to access with ngFor.
I am able to reach the first part of the data with the first ngFor (app_name, time_stamp etc)
But for some reason I am not getting to the nested object of test_cases. When I try it breaks the whole page and the console keeps telling me "Cannot read property 'test_cases' of undefined" and I can't seem to figure out why...
(first part of) data inside the component:
export class AppComponent {
tests = TESTS;
var TESTS: Test[] = [
{
"app_name": "website",
"time_stamp": "2018-01-20T12:00:00Z",
"test_cases": [
{
"test_name": "View article",
"status": true,
}]
}]
HTML partial:
<div id="tested-app" *ngFor = "let item of tests">
<h2>----<span> {{ item.app_name }} </span>----</h2>
<p id="time"> Time: <span> {{item.time_stamp}} </span> </p>
</div>
<div class="module" *ngFor="let subItem of item.test_cases">
<h3>{{subItem.test_name}}</h3>
</div>
For peeps who are struggling with this:
John Montgomery and Andres M answered this in the comments, I had to put the second div inside the first.