在 Mat 表中对异步进行垫排序,而 MatPaginator 不起作用,数据源在模板中异步分配



我正在尝试将matSort添加到这个已经工作和现有的MatTable中。我试图实现我在另一个线程上发现的东西 mat-sort 不适用于 mat-table,因为它看起来像是在描述同样的问题,但无法设法让它工作。我相信原因之一可能是我的数据源是在模板中异步计算的,而不是在我认为的 TS 文件中计算的。 为了清楚起见,我之前更改了它检索数据源的方式,我将其移动到 TS 文件,但 UI 仍然没有更新。

这里是代码的简化版本:

模板:

<table matSort mat-table [dataSource]="(searchMode === 'shift') ? shifts : (searchMode === 'booking') ? bookings">
<ng-container matColumnDef="orgName">
<th mat-header-cell *matHeaderCellDef  mat-sort-header> Organisation </th>
<td mat-cell *matCellDef="let element"> {{element.orgName}} </td>
</ng-container>
<ng-container matColumnDef="workerName">
<th mat-header-cell *matHeaderCellDef  mat-sort-header> Worker </th>
<td mat-cell *matCellDef="let element"> {{element.workerName}} </td>
</ng-container>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 20, 50, 100]" [pageSize]="20" [length]="total" (page)="onPageChange()" showFirstLastButtons></mat-paginator>

TS 文件:

import {MatTable, MatTableDataSource} from '@angular/material/table';
import {MatPaginator} from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
export class TsGenerationSearchTableComponent implements OnInit, OnChanges, AfterViewInit {
dataSource = new MatTableDataSource<Shift>();
@ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
@ViewChild(MatSort, {static: false}) sort: MatSort;
selectedWeekend: string;
selectedWeekStart: string;

ngOnInit() {
this.dataSource.paginator = this.paginator;
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}

onPageChange() {
const data: GetShiftTimesheetData = {
action: (this.searchMode === 'shift') ? 'PageGetShiftsForTsAction' : (this.searchMode === 'booking') ? 'PageGetBookingsForTsAction',
weekStartDate: this.selectedWeekStart,
weekEndDate: this.selectedWeekend,
paginator: {
pageSize: this.paginator.pageSize,
pageIndex: this.paginator.pageIndex
}
};
this.search.emit(data);
}

排序在 UI 中绝对不可见。我试图订阅ngOnChanges,看看它是否至少被看到过,就像这样:

ngOnChanges(changes: SimpleChanges): void {
if (this.dataSource && this.paginator && this.sort) {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.sort.sortChange.subscribe(val => {
console.log(val);
});
}
}

日志显示它至少对sortChange做出了反应:

{active: "workerName", direction: "asc"}

{active: "workerName", direction: "desc"}

但 UI 中没有任何内容。我尝试在订阅中执行this.dataSource.sort = val;,但抛出错误ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

欢迎任何帮助/提示。非常感谢大家。

您可以尝试以编程方式创建表元素,并仅在数据可用时呈现它。

1(使用mat-table为表创建一个单独的组件和模板。

2(导入该组件并将 ComponentFactoryResolver 类注入到 TsGenerationSearchTableComponent 类中。

import { ComponentFactoryResolver } from '@angular/core';
import { MyCustomMatTableComponent } from 'your/path/to/component';

export class TsGenerationSearchTableComponent implements OnInit {
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
.... 

3(在传入表的模板中使用占位符 via 指令。 这个占位符将公开ViewContainerRef,这是你需要的。(创建并在应用程序模块中声明占位符指令。

placeholder.directive.ts:

import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appPlaceholder]'
})
export class PlaceholderDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}

tsGenerationSearchTableComponent.html:

<!-- Add this where ever you want your table to be rendered -->
<ng-template appPlaceholder></ng-template>

4(在 tsGenerationSearchTableComponent.ts 中添加占位符的 ViewChild 选择器:

@ViewChild(PlaceholderDirective) yourMatTableComponent: PlaceholderDirective; // By passing in 
a class to ViewChild, it will find the first instance of said class.

5(订阅数据源获取...并使用组件工厂解析程序仅在成功检索数据时呈现表。

this.fetchData.subscribe((data) => {
const customMatTableFactory = this.componentFactoryResolver.resolveComponentFactory(MyCustomMatTableComponent); 
const viewContainerRef = this.matTablePlaceHolder.viewContainerRef;
hostViewContainerRef.clear(); // This will clear anything that was previously rendered in the ViewContainer.
const componentRef = viewContainerRef.createComponent(customMatTableFactory);
})

我通过以下方式解决了这个问题。基本上,dataSource是从商店直接传递的,因此无论我在 TS 文件中的努力如何,排序都不会发生。

所以首先我像这样更改数据源:<table matSort mat-table [dataSource]="dataSource">,在 TS 文件中,我创建了一个initialiseDataSource()初始化它的方法,该方法在ngOnInit()中调用。

initialiseDataSource() {
const dataSource = this.searchMode === 'timesheet' ? this.timesheets : this.shifts);
this.dataSource = new MatTableDataSource<Shift | Timesheet>(dataSource);
setTimeout(() => {
this.dataSource.sort = this.sort;
});
}

它实际上再简单不过了。这个问题的最大收获是排序需要应用于本地数据源才能发生,而就我而言,事实并非如此。

最新更新