NG-ZORRO可编辑行表格(editRowTable)使用焦点(blur)如何实现单行编辑

272 阅读3分钟

说实话我是不太清楚这篇博客的标题该怎么写
因为这并不是一篇科普或技术文章,而是记录我遇到的问题
但是这个问题的解决方法或者说思路非常有意思,还是打算记录一下XD
这里的某些代码命名会有点儿蠢,因为我是后接手这个页面的,与我无瓜!

初始功能描述

NG-ZORRO的表格,单击单元格可以进入该行的编辑模式,该行单元格均变为Input框。

表格在文档中的位置 Table(表格) | NG-ZORRO

当Input框失去焦点后会重新进入只读模式,并保存已编辑的内容。

image.png

由于整篇代码的量比较大,所以接下来均会用编号这一列的代码用作示例。

html代码:

<nz-table #editRowTable nzBordered [nzData]="listOfData" nzTableLayout="fixed" class="NZTable"
    [nzShowPagination]="false" [nzFrontPagination]="false">
    <thead>
        <tr>
            <th nzWidth="5%">编号</th>
        </tr>
    </thead>
    <tbody>
        <td (click)="startEdit(data.position)">{{ data.id15 }}</td>
        </ng-container>
        <ng-template #editTemplate>
            <td><input type="text" nz-input [(ngModel)]="editCache[data.position].data.id15" (blur)="saveEdit(data.position)" /></td>
        </ng-template>
        </tr>
    </tbody>
</nz-table>

ts代码:

// 面料表格所用编辑函数
  startEdit(id: string): void {
    this.listOfData.forEach(index => {
      if (index['position'] == id) {
        this.editCache[index['position']].edit = true;
      } else {
        this.editCache[index['position']].edit = false;
      }
    })
  }

  saveEdit(id: string | number): void {
    const index = this.listOfData.findIndex(item => item.position === id);
    Object.assign(this.listOfData[index], this.editCache[id].data);
    this.listOfData = [...this.listOfData];
    this.editCache[id].edit = false;
    this.isEdit = true;
  }

产品需求

由于编辑模式和只读模式是基于单元格的函数进行的,也就是说我进入A单元格的编辑模式后,是该行全部进入编辑模式,当我点击B单元格的input框时,由于触发了失去焦点函数,直接退出了编辑模式,很不方便。

产品希望在某行进入编辑模式的时候,该行的input框可以随意点击不会退出。

解决思路

需要知道的是,【失去焦点-保存数据】这个行为仅仅是在编辑模式和只读模式之间切换的时候自动触发的,模拟Excel那种保存的方式(这里指的是展现的数据保存,而不是文件的保存)

那么我们就可以放弃【失去焦点】才会【保存数据】,而将【保存数据】这个行为自行控制。

在单行数据随意编辑的情况下,什么时候才会触发【保存数据】这个行为呢,那就是跨行编辑的时候,从第x行切换到第y行的时候,我们就知道用户完成了这一行的编辑,触发保存即可。

所以我定义了一个字段positionIndex,用于存储用户当前的所在行,当进入编辑模式回传的positionpositionIndex不相同时,就代表用户跨行编辑了。

具体实现

html代码:

<nz-table #editRowTable nzBordered [nzData]="listOfData" nzTableLayout="fixed" class="NZTable"
    [nzShowPagination]="false" [nzFrontPagination]="false">
    <thead>
        <tr (click)="updateEditCache()">
            <th nzWidth="5%">编号</th>
        </tr>
    </thead>
    <tbody>
        <td (click)="startEdit(data.position)">{{ data.id15 }}</td>
        </ng-container>
        <ng-template #editTemplate>
            <td><input type="text" nz-input [(ngModel)]="editCache[data.position].data.id15" /></td>
        </ng-template>
        </tr>
    </tbody>
</nz-table>

html代码其实没有什么变动,只在表头添加了一个click函数pdateEditCache(),可以通过点击表头退出编辑模式触发保存。

ts代码:

 // 判断鼠标目前在第几行
  positionIndex = 100;
 // 面料表格所用编辑函数
  startEdit(id: string): void {
    // 只有存的索引不等于id时,意味着跨行进入了编辑模式,则保存上一行的数据
    if (Number(id) !== this.positionIndex && this.positionIndex !== 100) {
      this.saveEdit(this.positionIndex);
    }
    // 当进入编辑模式时赋值positionIndex,代表当前用户所在的行数
    this.positionIndex = Number(id);
    // 进入编辑模式
    this.listOfData.forEach(index => {
      if (index['position'] == id) {
        this.editCache[index['position']].edit = true;
      } else {
        this.editCache[index['position']].edit = false;
      }
    })
  }

  // 退出编辑模式,且对数据进行保存
  saveEdit(id: string | number): void {
    const index = this.listOfData.findIndex(item => item.position === id);
    Object.assign(this.listOfData[index], this.editCache[id].data);
    this.listOfData = [...this.listOfData];
    this.editCache[id].edit = false;
    this.isEdit = true;
  }

这一块代码其实并不多,看起来也非常简单,是因为这是我最后已经解决的成果代码。

最开始的时候我是陷入了一个很大的误区,虽然我刚开始的时候就使用了positionIndex这个字段,但我一直在html中使用焦点去触发【退出编辑模式并保存】。

我其实是将【点击-失焦-触发】的流程定死了,并没有想到【触发】可以不使用【失焦】的方式,可以在代码中自己掌控。