htmlangulartypescriptangular-signalsangular20

How to iterate over a Angular signal object in the html by using @for


In the html, I have to iterate over a WritableSignal object variableList(), but this html code will not run the loop unless the json string of the variableList() will show correctly in the same html.

html:

show JSON of variableList() : {{variableList() | json }}

@for (variable of variableList(); track [$index]; let i = $index) {   <!-- by this loop the UI look will generated by the variableList array -->
  loop test: {{i}}
}

And

variableList = signal<TVariable[]>([]);

The complete code is on Demo @ stackblitz


Solution

  • First we define the let i = $index, then we set the track by to the index we initialized in the previous step.

    ...
    @for (variable of variableList(); let i = $index; track i) {
      loop test:
      ...
    }
    ...
    

    The main problem was, that we defined the signal to be of type array. But in the update method, we are performing Object Destructuring ({ ...someObj }) instead of array destructuring ([ ...someArr ]).

    constructor() {
      this.variableList.update((v: TVariable[]) => {
        v.push(this.x(), this.y());
        return [...v];  // <- changed here!
      });
    }
    

    Full Code:

    import { bootstrapApplication } from '@angular/platform-browser';
    import { Component, signal } from '@angular/core';
    
    import { FormsModule } from '@angular/forms';
    import { JsonPipe } from '@angular/common';
    
    @Component({
      selector: 'app-root',
      imports: [FormsModule, JsonPipe],
      template: `
          <h1> {{ title }}  </h1>
    <hr>
    
    show JSON of variableList() : {{variableList() | json }}
    <hr>
    here shuld be the loop:
    
    @for (variable of variableList(); let i = $index; track i) {
      loop test:
    
      <table>
        <tr>
          <td>
            {{variable.name}} :
          </td>
          <td>
            <input
              [(ngModel)]='variable.index'>
          </td>
          <td>
            <input
              [(ngModel)]='variable.subindex'>
          </td>
          <td>
            <input
              [(ngModel)]='variable.value'>
          </td>
        </tr>
      </table>
    
     }
          
          
          `,
    })
    export class App {
      protected title = 'Angular Goes Functional';
    
      x = signal<TVariable>({
        name: 'X',
        value: 11,
        unit: 'N',
        index: '',
        subindex: '',
      });
    
      y = signal<TVariable>({
        name: 'Y',
        value: 33,
        unit: 'mm',
        index: '',
        subindex: '',
      });
    
      variableList = signal<TVariable[]>([]);
    
      constructor() {
        this.variableList.update((v: TVariable[]) => {
          v.push(this.x(), this.y());
          return [...v];
        });
      }
    }
    
    type TVariable = {
      name: string;
      index: string;
      subindex: string;
      value: number;
      unit: string;
      ID?: string;
    };
    
    bootstrapApplication(App);
    
    

    Stackblitz Demo