为什么通过事件处理程序从 html 传递到组件的 HTMLElement 指向错误的 html 元素?

Why HTMLElement passed to the component from html via event handler points to the wrong html element?

我有一个 table,我想通过点击事件 hadler 将 table 单元格的 HTMLElement 传递给组件。在开始时,我有指向正确 table 单元格的指针,但在我手动初始化更改检测后,指针指向错误的单元格(正确单元格的下一个)

我不知道为什么会这样。我在更改检测初始化之前和之后使用 console.log(tableCell) 创建了示例(AppComponent 中的方法 setEditMode

https://stackblitz.com/edit/angular-module-sandbox-btszav?file=src/app/app.component.html

app.component.html

    <button (click)="showClipboardText()">Fill the table</button>
    <table id="table" (click)="showTarget($event)">
      <thead>
        <tr>
          <th *ngFor="let colName of colNames">
            {{ colName }}
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let rowData of data; let rowIndex = index">
          <td
            #tableCell
            *ngFor="
              let cellData of rowData.length
                ? rowData
                : [].constructor(colNames.length);
              let colIndex = index
            "
            [attr.data-col-name]="colNames[colIndex]"
            (click)="setEditMode(rowIndex, colIndex, tableCell)"
          >
            {{ cellData?.value }}
            <input
              type="text"
              (keydown)="saveEdit($event, rowIndex, colIndex)"
              (blur)="saveEdit($event, rowIndex, colIndex)"
              *ngIf="!!data[rowIndex][colIndex]?.isEditMode"
            />
          </td>
          <button (click)="addRow()">+</button>
        </tr>
      </tbody>
    </table>

app.component.ts

    import {
          ChangeDetectorRef,
          Component,
          ElementRef,
          QueryList,
          ViewChildren,
        } from '@angular/core';
        
        @Component({
          selector: 'my-app',
          templateUrl: './app.component.html',
          styleUrls: ['./app.component.css'],
        })
        export class AppComponent {
          @ViewChildren('tableCell', { read: ElementRef })
          tableCells: QueryList<ElementRef>;
        
          colNames = ['Client', 'Order', 'Total'];
        
          data: Array<Array<{ isEditMode?: boolean; value?: string }>> = [
            Array(this.colNames.length),
          ];
        
          activeCell: { row: number; col: number };
        
          constructor(private cd: ChangeDetectorRef) {}
        
          addRow(): void {
            this.data.push(Array(this.colNames.length));
          }
        
          setEditMode(row: number, col: number, tableCell: HTMLElement): void {
            console.log(tableCell.dataset['colName']);
        
            if (this.activeCell) {
              const previousCellData =
                this.data[this.activeCell.row][this.activeCell.col];
              previousCellData.isEditMode = false;
            }
            if (!!this.data[row][col]) {
              this.data[row][col].isEditMode = true;
              this.data[row][col].value = '';
            } else {
              this.data[row][col] = { ...this.data[row][col], isEditMode: true };
            }
            this.activeCell = { row, col };
            this.cd.detectChanges();
            console.log(tableCell.dataset['colName']);
          }
        
          saveEdit(event: Event, row: number, col: number): void {
            if ((<KeyboardEvent>event).key && (<KeyboardEvent>event).key !== 'Enter')
              return;
        
            const value = (<HTMLInputElement>event.target).value;
            const previousCellData =
              this.data[this.activeCell.row][this.activeCell.col];
            previousCellData.isEditMode = false;
        
            this.data[row][col].value = value;
          }
        }

工作 stackblitz:https://stackblitz.com/edit/angular-module-sandbox-cdbpbq?file=src/app/app.component.ts

你的问题归结为我们从一个大小为 3 的数组开始,但没有定义默认值。照片:

这样,我们每定义一个值,colIndex 就加一。如果像 colName 一样为 colIndex 设置数据属性,则可以检查此项。解决方案包括为您的行定义一个默认值。

data: Array<Array<{ isEditMode?: boolean; value?: string }>> = [
    [
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
    ],
  ];

但是,这也意味着我们需要更新我们的添加行方法,如下所示:

addRow(): void {
    this.data.push([
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
    ]);
  }

之前您所做的只是添加一个长度为 3 的数组,但其中没有定义任何单元格。