Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 ngModel against ngFor variables

Tags:

Is it not possible (or not yet possible) to use ngModel against values from ngFor? Is Angular trying to protect me from bad performance?

Works great: http://jsfiddle.net/langdonx/n5pjgev6/

<input type="text" [(ng-model)]="value">{{value}}

Does not work so great: http://jsfiddle.net/langdonx/n5pjgev6/1

<li *ng-for="#name of names">
    <input type="text" [(ng-model)]="name">{{name}}
</li>

EXCEPTION: Cannot reassign a variable binding name

I tried binding to the array as well, which... kind of works, but hijacks focus and also throws an exception: http://jsfiddle.net/langdonx/n5pjgev6/2/

<li *ng-for="#name of names; #i = index">
    <input type="text" [(ng-model)]="names[i]">{{name}}
</li>

EXCEPTION: LifeCycle.tick is called recursively

Edit:

I can get around the LifeCycle.tick issue using a more direct approach, but the focus is still stolen because ngFor redraws things: http://jsfiddle.net/langdonx/n5pjgev6/3/

<li *ng-for="#name of names; #i = index">
    <input type="text" [value]="names[i]" (input)="names[i] = $event.target.value">{{names[i]}}
</li>
like image 869
Langdon Avatar asked Oct 26 '15 13:10

Langdon


People also ask

What does [( ngModel )] mean?

The ngModel directive is a directive that is used to bind the values of the HTML controls (input, select, and textarea) or any custom form controls, and stores the required user value in a variable and we can use that variable whenever we require that value. It also is used during form validations.

Can I use ngModel without form?

standalone: When set to true, the ngModel will not register itself with its parent form, and acts as if it's not in the form.

Can't bind to ngModel since it isn't a known property of input Ng?

To fix Can't bind to 'ngModel' since it isn't a known property of 'input' error in Angular applications we have to import FormModule in app. module. ts file. If you are using FormBuilder class to create reactive form we have to import ReactiveFormsModule as well to avoid below error.


2 Answers

I think ngFor don't like tracking array elements which are primitive values having ngModel on them.

If you remove the ngModel inside the loop, it works.

It works too when I update jsfiddle with :

this.names = [{name: 'John'}, {name: 'Joe'}, {name: 'Jeff'}, {name: 'Jorge'}];

and

<li *ng-for="#n of names"><input type="text" [(ng-model)]="n.name">{{n.name}}</li>
like image 146
bertrandg Avatar answered Oct 24 '22 04:10

bertrandg


A solution is to reference the value inside ngModel by its index. Therefore [(ngModel)]="names[index]".

But this is not sufficient because *ngFor tracks items by value. As soon as the value is changed the old value cannot be tracked. So we need to change the tracking function to return an index, thus trackBy: trackByIndex.

This issue is explained here.

Solution:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="text" 
        *ngFor="let name of names; let nameIndex = index; trackBy: trackByIndex"
        [(ngModel)]="names[nameIndex]"/>
      <br/>
      {{ names | json }}
    </div>
  `,
})
export class App {

  names: string[];

  constructor() {
    this.names = ['a', 'b', 'c'];
  }

  public trackByIndex(index: number, item) {
    return index;
  }
}
like image 20
andreim Avatar answered Oct 24 '22 03:10

andreim