0

I want to bind a model inside a ngFor loop to an input field via ngModel, but if I add another item to my list the value of the model will be visible in the model, but not in the view.

<div *ngFor="let model of models">
    <input [(ngModel)]="model.foo" name="foo">
    {{model | json}}
</div>
<button (click)="addEmptyListItem()">add</button>

If I enter bar in the view model | json will show { 'foo': 'bar' }, now if I add another element to the list model | json will still show { 'foo': 'bar' }, but nothing is visible in the input field.

My models variable comes from a BehaviorSubject

private $models: BehaviorSubject<Model[]> = new BehaviorSubject([]);
get models(): Model[] { return this.$models.getValue(); }

public addEmptyListItem(): void { 
    let models = this.models();
    models.push(new Model());
    this.$models.next(models);
}

which contains a list of Model

export class Model { public foo: string; }

Now if I exchange the [(ngModel)]="model.foo" name="foo" with [value]="model.foo" (input)="model.foo = $event.target.value":

<div *ngFor="let model of models">
    <input [value]="model.foo" (input)="model.foo = $event.target.value">
    {{model | json}}
</div>
<button (click)="addEmptyListItem()">add</button>

the view gets updated properly.

Question

Is there something I'm overlooking why [(ngModel)] isn't working?

And shouldn't [(ngModel)] also generate something similar to the above mentioned (see Two-way data binding in Angular 2)?

Community
  • 1
  • 1
Tobias Helbich
  • 447
  • 14
  • 32

1 Answers1

1

The name attribute has to be unique inside *ngFor loop., which you can make with index.

Change your code like:

<div *ngFor="let model of models;let i = index"">
    <input [(ngModel)]="model.foo" name="foo{{i}}">
</div>
anoop
  • 3,812
  • 2
  • 16
  • 28
  • 1
    Thank you very much! Is this documented somewhere - I was searching the angular documentation, but couldn't find this bit of information anywhere? – Tobias Helbich Jun 21 '17 at 14:27
  • this is not actually documented on angular website, but since core concept of angular is to use native HTML attributes\event, So this is actually the behaviour of HTML to have unique name inside form tag., and since ngModel works only after importing FormsModule, so it uses that behaviour., also same we did in `ng-repeat` for angularjs1.x – anoop Jun 21 '17 at 14:34
  • Just found a case where `name="foo{{i}}"` is not working - if I want to remove an element from my list (e.g. the first element of a list with 2 elements) and add another element, then the first element will be inside my model but is not displayed in the view (I think because the index changed). – Tobias Helbich Jun 21 '17 at 16:10
  • index will always remain unique, when you delete the element, then name property will change for every element inside *ngFor, – anoop Jun 22 '17 at 08:02
  • I followed your example, but it does not work if I delete an element (data not shown) - how can I fix this, or should I just use `[value]="model.foo" (input)="model.foo = $event.target.value"`? – Tobias Helbich Jun 22 '17 at 08:32
  • could you please provide some plunker, so i can help. without looking into code can't say, but that should be done with ngModel too for sure. – anoop Jun 22 '17 at 08:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/147347/discussion-between-anoop-and-tobias-helbich). – anoop Jun 22 '17 at 09:40