Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 -- Two-way bound text input blurring after each keyup when using NgFor [duplicate]

So in an Angular2 app I have a string array called 'recipe.ingredients', and I have a form set up to allow you to edit the ingredients, with buttons to add and remove text fields (and items in the array).

    <ul class="list-unstyled">
      <div class="row" *ngFor="let ingredient of recipe.ingredients; let i=index">
        <li>
          <div class="col-xs-4">
            <input
              size="20"
              type="text"
              class="form-control"
              [ngModel]="recipe.ingredients[i]"
              #t
              (blur)="recipe.ingredients[i]=t.value"
              required>
          </div>
          <div class="btn-group col-xs-2" role="group">
            <button
              type="button"
              class="btn btn-default btn-xs"
              (click)="recipe.ingredients.splice(i,1)">-</button>
            <button
              type="button"
              class="btn btn-default btn-xs"
              (click)="recipe.ingredients.splice(i+1,0,'')">+</button>
          </div>
        </li>
      </div>
    </ul>

You'll notice that I haven't done two way binding to recipe.ingredients[i] with [(ngModel)], and that's because I tried that and every time you typed a character, the text box would lose focus. I assume it has something to do with *ngFor stepping over the array. Anyways, for the time being this workaround was fine, but now I am adding some functionality and I need two way databinding to work. Any idea how I can refactor this to get that to work?

like image 264
David Sampson Avatar asked Dec 25 '22 04:12

David Sampson


1 Answers

Use trackBy:

<div class="row" *ngFor="let ingredient of recipe.ingredients; let i=index; 
 trackBy:customTrackBy">
  [(ngModel)]="recipe.ingredients[i]"
customTrackBy(index: number, obj: any): any {
  return index;
}

Credit to Günter: https://stackoverflow.com/a/36470355/215945, which can be found with this SO search: https://stackoverflow.com/search?q=%5Bangular2%5D+ngfor+ngmodel


Another way to solve the problem as shown here https://stackoverflow.com/a/33365992/215945 is to use an array of objects rather than an array of primitives. So instead of

recipe = { ingredients: ['salt', 'flour'] };

use

recipe = { ingredients: [{item: 'salt'}, {item: 'flour'}] };
like image 86
Mark Rajcok Avatar answered Dec 28 '22 09:12

Mark Rajcok