Angular 8-材质表在删除时未显示正确的数据

时间:2019-09-09 12:25:48

标签: angular angular-material

我有一个物料表,以选择形式显示可用选项。

我有一个根对象ngModel,用于保留选项。

从数据库中检索选项。

所以可以说我的根项目为menu。这样可以将饮料和水果记录在名为snacks的数组中,如下所示:

this.menu =
  {
    id: 1,
    snacks: [
      { fruitId: 1, drinkId: 1, deleted: false },
      { fruitId: 2, drinkId: 2, deleted: false },
      { fruitId: 3, drinkId: 2, deleted: false },
      { fruitId: 3, drinkId: 2, deleted: true },
    ]
  };

然后我们定义一些水果和饮料,用户可以选择:

this.fruits = [
  { id: 1, name: "Orange" },
  { id: 2, name: "Apple" },
  { id: 3, name: "Banana" },
  { id: 4, name: "Dragon fruit" }
];
this.drinks = [
  { id: 1, name: "Milk" },
  { id: 2, name: "Water" },
  { id: 3, name: "Juice" },
  { id: 4, name: "Soda" }
];

然后我们将其映射到表中:

<table mat-table [dataSource]="menuTableSource" #menuTable>

                        <ng-container matColumnDef="fruit">
                            <th mat-header-cell *matHeaderCellDef> Fruit </th>
                            <td mat-cell *matCellDef="let menuItem; let i = index;">
                                <mat-select [(ngModel)]="menu.snacks[i].fruitId" name="fruitId"
                                    #fruitId="ngModel">
                                    <mat-option *ngFor="let fruit of fruits" [value]="fruit.id">
                                        {{ fruit.name }}
                                    </mat-option>
                                </mat-select>
                            </td>
                        </ng-container>

                        <ng-container matColumnDef="drink">
                            <th mat-header-cell *matHeaderCellDef> Drink </th>
                            <td mat-cell *matCellDef="let menuItem; let i = index;">
                                <mat-select [(ngModel)]="menu.snacks[i].drinkId"
                                    name="drinkId" required>
                                    <mat-option *ngFor="let drink of drinks" [value]="drink.id">
                                        {{drink.name}}
                                    </mat-option>
                                </mat-select>
                            </td>
                        </ng-container>

                    <tr mat-header-row *matHeaderRowDef="menuTableColumns"></tr>
                    <tr mat-row *matRowDef="let row; columns: menuTableColumns;"></tr>
</table>

从该数组中删除一项并将表源数据设置为此并调用renderRows()后,表会删除最后一个条目 ,即使小吃阵列已按预期进行了更新

onRemoveMenuItem(menuItem: any): void {
const idx = this.menu.snacks.indexOf(menuItem);
if (idx >= 0) {
  this.menu.snacks[idx].deleted = true;
  this.menuTableSource.data = this.menu.snacks.filter(x => !x.deleted);
  this.menuTable.renderRows();
  }
}

这是错误还是必须以其他方式更新表?

请查看演示问题的堆叠闪电战:https://stackblitz.com/edit/angular-bzdjhj

2 个答案:

答案 0 :(得分:1)

更新: 再次查看您的代码后。我意识到您正在删除右边的行,并且数据更新很好,但是由于您正在显示fruits中的选择下拉菜单项,因此会给您带来混乱。

<ng-container matColumnDef="fruit">
  <th mat-header-cell *matHeaderCellDef> Fruit </th>
  <td mat-cell *matCellDef="let menuItem; let i = index;">
<mat-select [(ngModel)]="menu.snacks[i].fruitId" name="fruitId"
#fruitId="ngModel">
<mat-option *ngFor="let fruit of fruits" [value]="fruit.id">
  {{ fruit.name }}
</mat-option>
</mat-select>
</td>
</ng-container>

如果您删除第一项,则由于该<mat-option *ngFor="let fruit of fruits" [value]="fruit.id">,第二项再次在选择列表中显示为橙色。

>>>更新结束

您可以通过传递菜单项的索引并使用传递的索引将其从菜单中删除来做到这一点。

通过索引:

<ng-container matColumnDef="remove">
    <th mat-header-cell *matHeaderCellDef> &nbsp; </th>
    <td mat-cell *matCellDef="let menu; let i = index">
        <span class="fill-remaining-space"></span>
        <button mat-stroked-button color="primary" (click)="onRemoveMenuItem(i)">Remove</button>
    </td>
</ng-container>

您的逻辑将是:

onRemoveMenuItem(i): void {
  this.menu.snacks.splice(i, 1);
  this.menuTableSource.data = this.menu.snacks;
  this.menuTable.renderRows();
}

如果您不想删除该项目的属性,而只是添加已为其他进程删除的属性,则可以稍后再添加该项目的属性。

答案 1 :(得分:0)

再次看这个问题,我意识到我可能是个白痴。

Maihan为我指明了正确的方向。

当然,绑定到ngModel不起作用,因为ngModel在未过滤的集合上运行。

但是由于我想保留对已删除项目的引用,所以我添加了一个新数组。

deletedSnacks = [];

然后在我的removeMenuItem函数中,将小吃放入该数组中,将它们拼接起来,然后在提交给后端时,我就简单地将它们连接起来。

onRemoveMenuItem(menuItem: any): void {
const idx = this.menu.snacks.indexOf(menuItem);
if (idx >= 0) {
  this.menu.snacks[idx].deleted = true;
  this.deletedSnacks.push(this.menu.snacks[idx]);
  this.menu.snacks.splice(idx, 1);
  this.menuTableSource.data = this.menu.snacks;
  this.menuTable.renderRows();
  }
}