Angular mat-autocomplete - Dynamic add/delete item

2019-08-17 10:43发布

I'm trying to create a simple form with a dynamic number of mat-autocomplete fields. However, in some cases, the inputs' displayed values get lost.

Component's script

export class AutocompleteSimpleExample {
  availableItems = [{name: 'item1'}, {name: 'item2'}];
  items = [{name: 'item1'}, {}];

  addItem() {
    this.items.push({});
  }

  deleteItem(i: number) {
    this.items.splice(i, 1);
  }

  displayObject(obj) {
    return obj ? obj.name : null;
  }
}

Component's view

<form>
  <mat-form-field *ngFor="let item of items; let i = index">
    <input matInput [(ngModel)]="items[i]" [matAutocomplete]="itemAutocomplete" name="items[{{i}}]">

    <mat-autocomplete #itemAutocomplete="matAutocomplete" [displayWith]="displayObject">
      <mat-option *ngFor="let item of availableItems" [value]="item">{{item.name}}</mat-option>
    </mat-autocomplete>

    <button mat-button mat-icon-button matSuffix type="button" (click)="deleteItem(i)"><mat-icon>close</mat-icon></button>
  </mat-form-field>

  <button class="btnType01" mat-raised-button type="button" (click)="addItem()"><mat-icon>add</mat-icon>Add Item</button>
</form>

I've made a StackBlitz to showcase the issue. If you:

  1. Select an item in the second autocomplete field (e.g. Item 2)
  2. Remove the item from the first autocomplete field (using the x at the end of the field)
  3. Click Add Item to add another one

The first autocomplete field will then show an empty value, instead of keeping the one it had.

Could anyone help me figure out why the value is lost? Is this the wrong way of dealing with a dynamic number of autocomplete fields?

1条回答
啃猪蹄的小仙女
2楼-- · 2019-08-17 11:27

angular can’t keep track of items in the array and has no knowledge of which items have been removed or added.

As a result, Angular needs to remove all the DOM elements that associated with the data and create them again. That means a lot of DOM manipulations.

but you can try with a custom trackby :

<form>
    <mat-form-field *ngFor="let item of items; let i = index; trackBy:customTrackBy">
        <input matInput [(ngModel)]="items[i]" [matAutocomplete]="itemAutocomplete"
                     name="items[{{i}}]">

    <mat-autocomplete #itemAutocomplete="matAutocomplete" [displayWith]="displayObject">
            <mat-option *ngFor="let item of availableItems" [value]="item">{{item.name}}      </mat-option>
        </mat-autocomplete>

    <button mat-button mat-icon-button matSuffix type="button" (click)="deleteItem(i)"><mat-icon>close</mat-icon></button>
  </mat-form-field>

  <button class="btnType01" mat-raised-button type="button" (click)="addItem()"><mat-icon>add</mat-icon>Add Item</button>


</form>

ts:

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

DEMO

查看更多
登录 后发表回答