为什么通过事件处理程序从 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 的数组,但其中没有定义任何单元格。
我有一个 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 的数组,但其中没有定义任何单元格。