4

I've got an array of items displayed in inputs using ngModel. I use an ngFor directive inside a form with a basic control (required). The list doesn't display corrrectly : it's always the last item of the array which is displayed. If i use mustache syntax to display the array outside inputs, it's ok. If i remove the form and the control it's ok. You can test it here : plunker. Here is the code :

    @Component({
  selector: "my-app",
  providers: [],
  template: "
    <div>
      <form [formGroup]="personControl">
        <div *ngFor="let person of persons; let i = index">
          index : {{i}}<br/>
          label : {{person.label}}<br/>
          value : {{person.value}}<br/>
          <input type="text" 
                 maxlength="30" 
                 [id]="'label-'+person.id" 
                 [(ngModel)]="person.label"
                 formControlName="personLabel"/>
          <input type="text" 
                 maxlength="30" 
                 [id]="'value-'+person.id" 
                 [(ngModel)]="person.value"
                 formControlName="personValue"/>
        </div>
      </form>
    </div>
  ",
  directives: [REACTIVE_FORM_DIRECTIVES]
})
export class App {
  private personControl: FormGroup;
  private persons : Person[];
  constructor(private _formBuilder: FormBuilder) {
    this.persons = PERSONS;
    this.personControl = this._formBuilder.group({
      personLabel : new FormControl("", 
        [
          Validators.required
        ]),
        personValue : new FormControl("", 
        [
          Validators.required
        ])
    });

  }
}

export class Person {
  id: number;
  label: string;
  value : number;
}

const PERSONS: Person[] = [
  { id: 1, label: "Person One", value : 10 },
  { id: 2, label: "Person Two", value : 20 },
  { id: 3, label: "Person Three", value : 30 }
];

I try to have a look into formArrayName but it seems that it doesn't work with several inputs and you can't use ngModel. Somebody has an idea?

I use angular 2.0.0-rc.4 and forms 0.2.0

2 Answers 2

1

formControlName="personLabel" and formControlName="personValue" must be unique. They are taking the last label and value because the last object inside persons is overriding the previous ones.

You must define a unique FormControl for each:

this.personControl = new FormGroup({
  personLabel0 : new FormControl('', 
    [
      Validators.required
    ]),
    personValue0 : new FormControl('', 
    [
      Validators.required
    ]),
    personLabel1 : new FormControl('', 
    [
      Validators.required
    ]),
    personValue1 : new FormControl('', 
    [
      Validators.required
    ]),
    personLabel2 : new FormControl('', 
    [
      Validators.required
    ]),
    personValue2 : new FormControl('', 
    [
      Validators.required
    ])
});

And you can dynamically adjust formControlName with a function:

public getName(word, i) {
    return "person" + word + i;
}

And you can call that function from the template:

<div *ngFor="let p of persons; let i = index">
      index : {{i}}<br/>
      label : {{p.label}}<br/>
      value : {{p.value}}<br/>
      <input type="text" 
             maxlength="30" 
             [id]="'label-'+p.id" 
             [(ngModel)]="p.label"
             formControlName="{{getName('Label', i)}}"
             placeholder="{{p.id}}"/>
      <input type="text" 
             maxlength="30" 
             [id]="'value-'+p.id" 
             [(ngModel)]="p.value"
             formControlName="{{getName('Value', i)}}"/>
    </div>

I am not yet experienced in FormGroup so I do not know if there is a way to push new FormControls onto the FormGroup (personControl) object dynamically, continuously adjusting the names. If not would advise against the "model driven" forms.

Plunker: https://plnkr.co/edit/ERWA6GKX9VYADouPb6Z2?p=preview

Sign up to request clarification or add additional context in comments.

Comments

0

Ok, thanks for your reply. I didn't understand that the formControlName must be unique.

I create another plunk with the correction on the formControlName : https://plnkr.co/edit/chiCdN5A7Vb4MCrAYaSE?p=info

Here is the code :

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <form [formGroup]="personControl">
        <div *ngFor="let person of persons; let i = index">
          index : {{i}}<br/>
          label : {{person.label}}<br/>
          value : {{person.value}}<br/>
          <input type="text" 
                 maxlength="30" 
                 [id]="'label-'+person.id" 
                 [(ngModel)]="person.label"
                 [formControlName]="'personLabel'+person.id" />
          <input type="text" 
                 maxlength="30" 
                 [id]="'value-'+person.id" 
                 [(ngModel)]="person.value"
                 [formControlName]="'personValue'+person.id" />
        </div>
      </form>
    </div>
  `,
  directives: [REACTIVE_FORM_DIRECTIVES]
})
export class App {
  private personControl: FormGroup;
  private persons : Person[];
  constructor(private _formBuilder: FormBuilder) {
    this.persons = PERSONS;
    let ctrls = {};

    this.persons.forEach(((person: Person) => {
      ctrls[`personLabel${person.id}`] = new FormControl('', 
        [
          Validators.required
        ]);
        ctrls[`personValue${person.id}`] = new FormControl('', 
        [
          Validators.required
        ]);
    }).bind(this));
    this.personControl = this._formBuilder.group(ctrls);

  }
}

export class Person {
  id: number;
  label: string;
  value : number;
}

const PERSONS: Person[] = [
  { id: 1, label: 'Person One', value : 10 },
  { id: 2, label: 'Person Two', value : 20 },
  { id: 3, label: 'Person Three', value : 30 }
];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.