Как использовать ngModel внутри * ngFor с индексом? - PullRequest
0 голосов
/ 18 июня 2020

Я генерирую динамику c mat-inputs, используя *ngFor. И я хочу сохранить каждое значение [(ngModel)] в другом массиве (а не в *ngFor), используя индекс элементов *ngFor. Вот что я делаю:

<div  *ngFor="let item of items;let id = index;">

<mat-form-field >
  <mat-select  [(ngModel)]="differentArray[id].first"  (ngModelChange)="onSelection()">
    <mat-option *ngFor="let number of arrayOfNumbers" [value]="number">{{number}}</mat-option>
  </mat-select>
</mat-form-field> 

<mat-form-field>
  <mat-select  [(ngModel)]="differentArray[id].second"  (ngModelChange)="onSelection()">
    <mat-option *ngFor="let number of arrayOfNumbers" [value]="number" >{{number}}</mat-option>
  </mat-select>
</mat-form-field>

<mat-form-field >
  <mat-select  [(ngModel)]="differentArray[id].third"  (ngModelChange)="onSelection()">
    <mat-option *ngFor="let number of arrayOfNumbers" [value]="number">{{number}}</mat-option>
  </mat-select>
</mat-form-field>

</div>

Но значения для всех разных *ngFor становятся одинаковыми. Почему так происходит? И как мне правильно это сделать с каждым id элемента?

1 Ответ

0 голосов
/ 18 июня 2020

Исходя из того, как вы определили привязки свойств к директивам [(ngModel)], differentArray должен иметь форму

differentArray = [
  { first: 0, second: 0, third: 0 },
  { first: 0, second: 0, third: 0 },
  { first: 0, second: 0, third: 0 }
]

Рабочий пример: Stackblitz

Обновление

Вместо того, чтобы помещать его в родительский объект, вы можете привязать декоратор @Input() к сеттеру и инициализировать differentArray непосредственно в дочернем элементе. Но независимо от того, что вы делаете в родительском или дочернем, самое важное, что нужно помнить, это то, что объект будет выталкиваться по ссылке. Таким образом, любые изменения в одном из объектов также повлияют на другие объекты. Поэтому вам нужно использовать JSON.parse(JSON.stringify(obj)) для создания глубоких клонов obj. Попробуйте следующий

parent.component.ts

export class ParentComponent {
  items = ['item1', 'item2', 'item3'];
  arrayOfNumbers = [1, 2, 3, 4, 5];
  differentArray = { first: 0, second: 0, third: 0 };

  constructor() {}
}

parent.component. html

<app-child [items]="items" [arrayOfNumbers]="arrayOfNumbers" [differentArray]="differentArray"></app-child>

child.component.ts

export class ChildComponent {
  _differentArray: Array<any> = [];

  @Input() items: Array<any> = [];
  @Input() arrayOfNumbers: Array<any> = [];
  
  @Input() set differentArray(obj: any) {
    this.items.forEach(item => 
      // notice the deep clone using `JSON.parse(JSON.stringify(obj)` here
      this._differentArray.push(JSON.parse(JSON.stringify(obj)))
    );
  }

  constructor() {}

  onSelection() {
    console.log('selected: ', this._differentArray);
  }
}

child.component. html

<div *ngFor="let item of items; let id=index;">
  <mat-form-field >
    <mat-select  [(ngModel)]="_differentArray[id].first"  (ngModelChange)="onSelection(id)">
      <mat-option *ngFor="let number of arrayOfNumbers" [value]="number">{{number}}</mat-option>
    </mat-select>
  </mat-form-field> 

  <mat-form-field>
    <mat-select  [(ngModel)]="_differentArray[id].second"  (ngModelChange)="onSelection(id)">
      <mat-option *ngFor="let number of arrayOfNumbers" [value]="number" >{{number}}</mat-option>
    </mat-select>
  </mat-form-field>

  <mat-form-field >
    <mat-select  [(ngModel)]="_differentArray[id].third"  (ngModelChange)="onSelection(id)">
      <mat-option *ngFor="let number of arrayOfNumbers" [value]="number">{{number}}</mat-option>
    </mat-select>
  </mat-form-field>
</div>

Рабочий пример: Stackblitz

...