Home > Software engineering >  Angular problem with *ngFor and array of object from a function
Angular problem with *ngFor and array of object from a function

Time:11-09

I am trying to use component MatSelect from Angular Material, on the iteration part i am using an array of objects that comes from a function

Simple scenario that i got from Angular Material Website

html file

<h4>Basic mat-select</h4>
<mat-form-field appearance="fill">
  <mat-label>Favorite food</mat-label>
  <mat-select>
    <mat-option *ngFor="let food of foods" [value]="food.value">
      {{food.viewValue}}
    </mat-option>
  </mat-select>
</mat-form-field>

ts file

import {Component} from '@angular/core';

interface Food {
  value: string;
  viewValue: string;
}

/**
 * @title Basic select
 */
@Component({
  selector: 'select-overview-example',
  templateUrl: 'select-overview-example.html',
})
export class SelectOverviewExample {
  foods: Food[] = [
    {value: 'steak-0', viewValue: 'Steak'},
    {value: 'pizza-1', viewValue: 'Pizza'},
    {value: 'tacos-2', viewValue: 'Tacos'},
  ];
}

Simple scenario of what i am trying to do and it doesn't just work but also it freezes the web app, no error displayed on console

html file

<h4>Basic mat-select</h4>
<mat-form-field appearance="fill">
  <mat-label>Favorite food</mat-label>
  <mat-select>
    <mat-option *ngFor="let food of data()" [value]="food.value">
      {{food.viewValue}}
    </mat-option>
  </mat-select>
</mat-form-field>

ts file

import {Component} from '@angular/core';

interface Food {
  value: string;
  viewValue: string;
}

/**
 * @title Basic select
 */
@Component({
  selector: 'select-overview-example',
  templateUrl: 'select-overview-example.html',
})
export class SelectOverviewExample {
  foods: Food[] = [
    {value: 'steak-0', viewValue: 'Steak'},
    {value: 'pizza-1', viewValue: 'Pizza'},
    {value: 'tacos-2', viewValue: 'Tacos'}
  ];

  data(): Food[] {
    return [
      {value: 'steak-0', viewValue: 'Steak'},
      {value: 'pizza-1', viewValue: 'Pizza'},
      {value: 'tacos-2', viewValue: 'Tacos'}
    ];
  }
}

Extra info, this works fine if the return value of the function is an array of strings

html file

<h4>Basic mat-select</h4>
<mat-form-field appearance="fill">
  <mat-label>Favorite food</mat-label>
  <mat-select>
    <mat-option *ngFor="let food of data()" [value]="food">
      {{food}}
    </mat-option>
  </mat-select>
</mat-form-field>

ts file

import {Component} from '@angular/core';

interface Food {
  value: string;
  viewValue: string;
}

/**
 * @title Basic select
 */
@Component({
  selector: 'select-overview-example',
  templateUrl: 'select-overview-example.html',
})
export class SelectOverviewExample {
  foods: Food[] = [
    {value: 'steak-0', viewValue: 'Steak'},
    {value: 'pizza-1', viewValue: 'Pizza'},
    {value: 'tacos-2', viewValue: 'Tacos'},
  ];

  foods2 = ['Steak', 'Pizza', 'Tacos'];

  data(): string[] {
    return ['Steak', 'Pizza', 'Tacos'];
  }
}

CodePudding user response:

The first scenario you have works for me because since I don't have mat-option component so no [value]="food.value". Maybe the problem is in the parameter that you are sending to the component. In fact, your third scenario maybe works because the parameter you are sending to the component is not food.value but food.

Hope this helps.

CodePudding user response:

The application got freeze because mat-option try to render all changes again. That's the way the first scenario is okay because the application knows nothing changes.

Solution use trackBy to tell ngFor for that do it use to compare changes.

<h4>Basic mat-select</h4>
<mat-form-field appearance="fill">
  <mat-label>Favorite food</mat-label>
  <mat-select>
    <mat-option *ngFor="let food of data(); trackBy: trackedValue" [value]="food.value">
      {{ food.viewValue }}
    </mat-option>
  </mat-select>
</mat-form-field>

Example: stackblitz

  • Related