【问题标题】:Mat Sort on asynchronous in Mat Table with MatPaginator not working, datasource assigned asynchronously in templateMat 表中的 Mat 异步排序,MatPaginator 不起作用,数据源在模板中异步分配
【发布时间】:2019-12-06 13:06:19
【问题描述】:

我正在尝试将 matSort 添加到这个已经工作和现有的 MatTable 中。我已经尝试实现我在 mat-sort not working on 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.

欢迎任何帮助/提示。非常感谢你们。

【问题讨论】:

    标签: angular asynchronous angular-material datasource mat-table


    【解决方案1】:

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

    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 这是你需要的。 (在您的应用模块中创建然后声明 PlaceholderDirective。)

    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) 订阅 dataSource fetch... 并仅在成功检索数据时使用 ComponentFactoryResolver 呈现您的表。

    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);
    })
    

    【讨论】:

    • 您好,非常感谢您花时间回答我的问题。我确实在周末解决了它,但您的解决方案对其他人仍然有用。非常感谢!
    • 哦,太好了。我之前在 MatSort 上遇到过类似的问题......所以我也会为您的解决方案添加书签。 :) 另外,如果您不介意对我的解决方案进行投票,我将不胜感激!
    【解决方案2】:

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

    所以首先我改变了这样的数据源: &lt;table matSort mat-table [dataSource]="dataSource"&gt; 并且,在 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;
        });
      }
    

    实际上再简单不过了。这个问题最大的收获是排序需要应用于本地数据源才能发生,而在我的情况下它不是。

    【讨论】:

      猜你喜欢
      • 2020-10-20
      • 2019-08-21
      • 2019-10-05
      • 2019-02-21
      • 2021-02-03
      • 1970-01-01
      • 2020-12-12
      • 2017-06-15
      • 1970-01-01
      相关资源
      最近更新 更多