admin管理员组

文章数量:1287511

The ponent model:

private SomeArray = [{ key: "Initial" }];

User can add/remove items dynamically:

addField() {
    this.SomeArray.push({ key: Math.random().toString() });
}

removeField(index: number) {
    this.SomeArray.splice(index, 1);
}

Template markup:

 <div class="col-xs-12">
     <button (click)="addField()" type="button">Add</button>
 </div>

 <div *ngFor="let field of SomeArray; let i = index;">
     <input [(ngModel)]="field.key" #modelField="ngModel" [name]=" 'SomeArray['+i+'].key' " type="text" class="form-control" required />
     <div [hidden]="modelField.pristine || !(modelField.errors && modelField.errors.required)" class="alert alert-danger">
        Required error
     </div>

    <button (click)="removeField(i)" class="btn btn-danger">Remove</button>
 </div>

This works untill user removes any item from SomeArray. If I add some two items initially:

and remove the one with 1 index:

then after adding another item Angular treat it as item has both 0 and 1 index (the new item "occupies" both two inputs):

(item with key 0.1345... is not displayed)

It's worth to noting items of SomeArray are as expected, but data binding fails. What can be the reason of it?

Update: Thanks to the ments of @Stefan Svrkota and @AJT_82 it's known for me the issue can be resolved by adding [ngModelOptions]="{standalone: true}" to the needed input. But I couldn't stop thinking about the reason of the issue in my cause, without setting standalone option (there is unique value for each name attribute so it's excepted nothing wrong here).

Finally I have found that behavior occurs when input elements are into <form> tag only - Plunker sample here (enclosing of template with form tag is the reason that issue).

Any ideas of this behavior?

The ponent model:

private SomeArray = [{ key: "Initial" }];

User can add/remove items dynamically:

addField() {
    this.SomeArray.push({ key: Math.random().toString() });
}

removeField(index: number) {
    this.SomeArray.splice(index, 1);
}

Template markup:

 <div class="col-xs-12">
     <button (click)="addField()" type="button">Add</button>
 </div>

 <div *ngFor="let field of SomeArray; let i = index;">
     <input [(ngModel)]="field.key" #modelField="ngModel" [name]=" 'SomeArray['+i+'].key' " type="text" class="form-control" required />
     <div [hidden]="modelField.pristine || !(modelField.errors && modelField.errors.required)" class="alert alert-danger">
        Required error
     </div>

    <button (click)="removeField(i)" class="btn btn-danger">Remove</button>
 </div>

This works untill user removes any item from SomeArray. If I add some two items initially:

and remove the one with 1 index:

then after adding another item Angular treat it as item has both 0 and 1 index (the new item "occupies" both two inputs):

(item with key 0.1345... is not displayed)

It's worth to noting items of SomeArray are as expected, but data binding fails. What can be the reason of it?

Update: Thanks to the ments of @Stefan Svrkota and @AJT_82 it's known for me the issue can be resolved by adding [ngModelOptions]="{standalone: true}" to the needed input. But I couldn't stop thinking about the reason of the issue in my cause, without setting standalone option (there is unique value for each name attribute so it's excepted nothing wrong here).

Finally I have found that behavior occurs when input elements are into <form> tag only - Plunker sample here (enclosing of template with form tag is the reason that issue).

Any ideas of this behavior?

Share Improve this question edited Jun 11, 2017 at 0:06 Ilya Loskutov asked Jun 10, 2017 at 18:24 Ilya LoskutovIlya Loskutov 2,2012 gold badges23 silver badges39 bronze badges 4
  • 1 stackoverflow./questions/41265761/… – Stefan Svrkota Commented Jun 10, 2017 at 18:26
  • @Stefan Svrkota solved, thank) – Ilya Loskutov Commented Jun 10, 2017 at 18:34
  • @AJT_82 I think [name]=" 'SomeArray['+i+'].key' " returns unique name value (with index of iteration i)? am I wrong? – Ilya Loskutov Commented Jun 10, 2017 at 19:07
  • @Mergasov Nevermind what I was babbling about :D Yeah, ngModelOptions is a good solution here since I guess you don't really need the name attribute here in the form (I assume it is), as you are using two-way-binding. – AVJT82 Commented Jun 10, 2017 at 19:24
Add a ment  | 

1 Answer 1

Reset to default 13

The reason why it happens is ngFor mixes name properties when you delete some item.

When you use ngModel inside form each ngModel control will be added to form controls collection.

Let's see what happens if we have added three items and clicked on Remove the second

1) Step1 - SomeArray[1].key exists in collection controls

2) Step2 - SomeArray[1].key has been removed from controls collection

3) Step3 - Html looks like

4) Step4 We are adding a new item

So formGroup returns existing item.

How we can solve it?

1) Don't wrap our controls in form tag

2) Add ngNoForm attribute to form

<form ngNoForm>

3) Use

[ngModelOptions]="{standalone: true}

With all three solutions above:

  • We can remove [name] property binding

  • We can't use the built in Form group validation

4) Use trackBy for ngFor

template.html

<div *ngFor="let field of SomeArray; let i = index; trackBy: trackByFn">

ponent.ts

trackByFn(i: number) {
  return i;
}

Plunker Example

This way our built in form will work properly

本文标签: javascriptngModel cannot detect array changes correctlyStack Overflow