2-way data binding to an array element in an *ngFor? (Ionic 2 RC1)

I made a list of inputs like this:

<ion-list>
  <ion-item *ngFor="let item of itemList; let i = index;">
    <ion-label stacked primary>An item</ion-label>
    <ion-input type="text" [(ngModel)]="itemlist[i]"></ion-input>
  <ion-item>   <ion-list>

It works fine functionally, except for one strange, bad thing: Every time I type a character in the input field, it loses focus. So I have to click the input field again to enter the next character. This happens in a browser (ionic serve) and on an iPhone (ionic run). Is there a trick to this I am missing?

(At first I thought it should be [(ngModel)]=“item” but that errors out with “Unhandled Promise rejection: Cannot assign to a reference or variable!”)

It has something to do with the *ngFor, because this does not have a problem:

<ion-list>
  <ion-item>
    <ion-label stacked primary>An item</ion-label>
    <ion-input type="text" [(ngModel)]="itemlist[0]"></ion-input>
  <ion-item>   <ion-list>

I put a plunker together for it http://plnkr.co/edit/tJFPUR?p=preview but unfortunately the plunker doesn’t run at all when I add the ngModel with the array element in the *ngFor.

I am running Ionic 2 RC1.

@lannie Your issue is discussed here:

I think that your list is reloaded again by ngFor when you change one field value, and that is why it is losing the focus. You can add a trackBy to determine if the list must or must not be reloaded. The code below seems to solve the issue:

<ion-list>
	<ion-item *ngFor="let item of itemList; let i = index; trackBy: customTrackBy">
		<ion-label stacked primary>An item</ion-label>
		<ion-input type="text" [(ngModel)]="itemList[i]"></ion-input>
	</ion-item>
</ion-list>

And in the .ts file:

itemList = ['thing zero', 'thing one', 'thing two', ''];

customTrackBy(index: number, obj: any): any {
	return index;
}

I hope it helps.

8 Likes

Yes indeed, lucasbasquerotto, that fixed it right up. Thanks so much!

You were missing something essential. ion-input works with attribute name. You also need to set this dynamically.

<ion-list>
	<ion-item *ngFor="let item of itemList; let i = index; trackBy: customTrackBy">
		<ion-label stacked primary>An item</ion-label>
		<ion-input type="text" [(ngModel)]="itemList[i]" [name]="'input-'+i"></ion-input>
	</ion-item>
</ion-list>
1 Like

I don’t see how this is useful, let alone essential.

this worked for me because without the ([name]="‘input-’+i"), the input field would only let me type 1 character then deselect the input. Thanks!