Angular 8 Nested Object Interpolation

Viewed 5390

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>
3 Answers

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