简体   繁体   中英

How to bind array of inputs to model in Angular

Could somebody help me with the following code and give me a reason why it does not work. I am creating a series of inputs from a string array and I want to bind each input value to its corresponding slot in the string array. Seems to be pretty standard, but I do not seem to grasp the issue.

I have tried the following two cases, but the Colors array (=string[]) remains empty!

<tr *ngFor="let color of Colors; let i = index;">
 <td>
  <mat-form-field>
      <input required matInput placeholder="Color ({{ i + 1}})"   [name]="'color_' + i" [(ngModel)]="color">
  </mat-form-field>
</td>
</tr>

<tr *ngFor="let color of Colors; let i = index;">
 <td>
  <mat-form-field>
   <input required matInput placeholder="Color ({{ i + 1}})"  [name]="'color_' + i" [(ngModel)]="Colors[i]">
  </mat-form-field>
</td>
</tr>

Afaik ngModel requires the variable to be a property of the class.

You should try using reactive forms

@Input() colors: string[];
public formGroup: FormGroup;
constructor(private formBuilder: FormBuilder) {
}

ngOnInit() {
  const formControls = {};
  this.colors.forEach(e => {
    formControls[e]: new FormControl(e);
  }
  this.formGroup = this.formBuilder.group(formControls);
}

Then in your html something like this}

<tr *ngFor="let color of Colors; let i = index;" [formGroup]="formGroup">
 <td>
  <mat-form-field>
      <input required matInput placeholder="Color ({{ i + 1}})"   [name]="'color_' + i" [formControlName]="color">
  </mat-form-field>
</td>
</tr>

I wrote that on the fly so don't know if it works. But with some tweaking it should.

您似乎忘记了关闭“ tr”标签。

Strings are immutable in JavaScript, meaning we cant bind ngModel to them. You could quite easily convert your array into an array on objects with the key color and the value of your strings. This would fix your binding issue. Here is some code. I also hacked together a stackbitz to show you.

However, I would recommend Joey gough's answer though. That code feels more correct and "the angular way" of solving this. Good luck!

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  Colors = [{color: 'stringColor1'}, {color: 'stringColor2'}]
}

<tr *ngFor="let item of Colors; let i = index;">
  {{i}}
 <td>
  <input required placeholder="Color ({{ i + 1}})" [name]="'color_' + i" [(ngModel)]="item.color">
</td>
</tr>

{{Colors | json}}

See: https://stackblitz.com/edit/angular-sj623x

It's possible using [(ngModel)] or ReactiveForms.

The problem if you use [(ngModel)] is that you can not iterate over the own array.

//***WRONG**, you change "Colors" in input and is iterating over Colors
//you see that your form is "unestable"
<div *ngFor="let color of Colors; let i = index;">
   <input required matInput placeholder="Color ({{ i + 1}})"  [name]="'color_' + i" [(ngModel)]="Colors[i]">
</div>

but you can use

<tr *ngFor="let color of ' '.repeat(Colors.length).split(''); let i = index;">
 <td>
  <mat-form-field>
   <input required matInput placeholder="Color ({{ i + 1}})"  
               [name]="'color_' + i" [(ngModel)]="Colors[i]">
  </mat-form-field>
</td>
</tr>
<hr/>
{{Colors|json}}

Yes is a work-around: not iterate over Colors, just over an array create on fly using String.repeat and split

' '.repeat(Colors.length).split('') //a string of same length that Colors.length

Using ReactiveForm, it's better use a FormArray

<div *ngIf="formArray" [formGroup]="formArray">
<tr *ngFor="let control of formArray.controls;let i=index">
 <td>
  <mat-form-field>
   <input matInput placeholder="Color ({{ i + 1}})"  [name]="'color_' + i" [formControl]="control">
  </mat-form-field>
</td>
</tr>
</div>
<hr/>
{{formArray?.value|json}}

You can see the stackblitz

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM