如何在不将焦点设置在数据表上的情况下从 EXTERNAL SELECTION 获取 DataTable 到 select/highlight?

How to get DataTable to select/highlight from EXTERNAL SELECTION without setting focus on datatable?

这不是重复的 post,正如我所看到的,但找不到任何具有外部状态更改的内容。这几天我一直在断断续续地搜索这个话题。

我正在做的是以下内容。

我的 UI 上有数据表和地图。 DataTable 列出了地图上的数据点。

我可以在 DataTable 上 select 和 multi select,突出显示数据上的行 table 并与地图交互并绘制突出显示的数据点。 我遇到的问题是,当我将地图用于 select 时,DataTable 不会反映地图上与该数据点一起出现的 selected 行,直到我将鼠标悬停在我的 DataTable 上'假设在后台触发某种刷新。我不必在 DataTable 中单击或执行任何操作,它会自动触发,然后显示我在地图中 select 编辑的所有点。

html 页面为 [selected] 绑定的变量被正确调用并且它的值被设置,它只是不反映行上的高亮直到鼠标进入DataTable区域。我不需要点击或做任何事情来触发它,它会在鼠标进入该区域后自行触发。

此外,我还尝试手动设置 table selected 值,例如

this.tableRef.selected = this.newRowSelection;

所以我的问题是 如何让 DataTable 在我制作外部 selection 时自动显示?

我不想删除 table 和重绘 DataTable,因为我觉得这不会创建良好的用户体验。

感谢对此提出的所有意见。

============================================= ==========

更新:2020 年 3 月 11 日,星期三

因此,经过更多测试和调试后,我可以确认我确实将 datatable.selected 值设置为应该 selected 的 [] 行。

但是,在我将鼠标悬停在数据上之前,行不会突出显示table。

有人对如何让数据table自动突出显示有任何建议吗?

============================================= ==========

如果没有可重现的示例,很难确定,但我认为这是因为您正在更新 angular 范围之外的 属性,可能是点击地图的结果这不受 angular 方式的限制。

您可以阅读有关更改检测的内容 here。基本上,angular 会在浏览器事件(鼠标单击、鼠标悬停、按键事件...)、ajax 调用以及 setTimeout 和 [=13] 上触发对其了解的所有组件的更改检测=].

如果您在 angular 不知情的情况下更新了某些组件 属性(例如,通过将点击绑定到您的地图而不使用 nangular 的点击处理程序),angular(和你的数据table)不会知道它并且不会刷新直到下一次变化检测(这是数据table的鼠标悬停)

因此,如果您在 angular 之外进行此类更改,则需要使用以下两种方法之一再次通知 angular 到 运行 更改检测。

将您的修改包装在 setTimeout

setTimeout(()=> this.tableRef.selected = this.newRowSelection);

这将触发整个应用程序的更改检测

明确通知 angular 再次 运行 更改检测

import {ChangeDetectorRef} from '@angular/core';
constructor(private cdr: ChangeDetectorRef) {}
//....
this.tableRef.selected = this.newRowSelection;
this.cdr.detectChanges();

请注意,这将仅适用于您从中调用此方法的组件(和子组件)。因此,如果您的地图和数据 table 在同一个组件中,这应该会立即起作用。否则,您可以将某些事件从地图组件传播到包含 table 的组件以了解何时调用此方法。

您也可以直接在 angular 的区域内执行您的操作

import {NgZone} from '@angular/core';
constructor(private ngZone: NgZone) {}
//...
this.ngZone.run(() => this.tableRef.selected = this.newRowSelection);

我有一个解决方案并不完美,但它工作得很好!在更新所选行之前,只需重新分配您的行 this.rows = [...this.rows];。它以某种方式触发数据的变化检测周期table。

如果您要动态更新 table 行,则每次获取新数据时都必须调用 refreshSelectedRow(例如在数据更新订阅中)。

如果您 运行 没有重新分配的代码,它仍然可以工作,但仅适用于下一行数据更新(例如来自订阅),您很可能会将一个新数组对象分配给 this.rows 无论如何。根据您的数据更新频率,您可能会有延迟。

export class MapComponent {
  SelectionType = SelectionType;

  @ViewChild('myTable') table: any;

  @Input() set selectedLotId(value: number | null) {
    this._selected = value;
    this.refreshSelectedRow(); 
  }

  private _selected: number | null;

  rows: Lot[] = [];

  constructor() {}

  this.carParkSub$ = this.store.lots$.subscribe((lots) => {
    this.rows = lots || [];

    // needs to call here as well, cause in my case
    // I am polling new data every 5s 
    this.refreshSelectedRow();
  });

  refreshSelectedRow() {
    if (!this.table) {
      return;
    }
    this.rows = [...this.rows]; //MUST BE RUN!. Otherwise datatable will not pick up changes to selected row;

    let selected = this.rows.find((row) => row.id == this._selected);
    this.table.selected = [];
    if (selected) {
      this.table.selected.push(selected);
    }
  }

}
<ngx-datatable #myTable 
[rows]="rows" 
[selectionType]="SelectionType.single" 
[trackByProp]="'id'">
  table columns and content here
</ngx-datatable>

在我的例子中,我使用 @Input() 道具从外部设置选定的行,而不是将绑定道具传递给模板中的 table 我使用编程方式 this.table.selected.push(selected);

注意:请记住,我从代码中删除了镇流器,因此简单的复制和粘贴将不起作用。