Connect method DataSource is not emitting all paginated rows for MatTable

ぐ巨炮叔叔 提交于 2021-02-02 09:56:53

问题


I am trying to use the DataSource interface to update MatTableData, using server-side pagination.

<div>

  <mat-table [dataSource]="dataSource" matSort matSortDisableClear>

    <ng-container matColumnDef="type">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-200 th-center"> Type</mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-200 th-center"> {{v.type}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="title">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-200 th-center"> Title</mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-200 th-center"> {{v.title}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="status">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-200 th-center"> Status</mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-200 th-center"> {{v.status}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="url">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-200 th-center"> Url</mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-200 th-center"> {{v.url}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="host">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-250 th-center"> Host </mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-250 th-center"> {{v.host}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="ipv4">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-250 th-center"> Ipv4 </mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-250 th-center"> {{v.ipv4}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="category">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="w-250 th-center"> Category 
    </mat-header-cell>
      <mat-cell *matCellDef="let v" class="w-250 th-center"> {{v.category}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="id">
      <mat-cell *matCellDef="let v"> {{v.id}} </mat-cell>
    </ng-container>


    <mat-header-row *matHeaderRowDef="getDisplayedColumns()"></mat-header-row>

    <mat-row class="element-row" *matRowDef="let row; columns: getDisplayedColumns();">
    </mat-row>
  </mat-table>

  <mat-paginator [length]="total" [pageSize]="10" [pageSizeOptions]="[5, 10, 25, 100]">

  </mat-paginator>

</div>



@Component({
  selector: 'kt-vulnerability-list',
  templateUrl: './vulnerability-list.component.html',
  styleUrls: ['./vulnerability-list.component.scss']
})
export class VulnerabilityListComponent implements OnInit, AfterViewInit, OnDestroy {

  displayColumns;
  dataSource: VulnerabilityDataSource
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;
  total = 1172;

  constructor(private globalEntityStore: GlobalEntityStore,
              private vulnerabilityDataService: VulnerabilityDataService,
              private activatedRoute: ActivatedRoute) {

  }

  ngOnInit(): void {
    // const store$ = this.globalEntityStore.state$;

    const tableConfig = new VulnerabilityTableConfig();
    this.displayColumns = tableConfig.configClient;

    this.dataSource = new VulnerabilityDataSource(this.vulnerabilityDataService);

    this.dataSource.loadVulns('ERA Home Security Ltd', '', 'asc', 0, 1);
  }

  ngAfterViewInit() {
    this.sort.sortChange
      .subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page)
      .pipe(
        untilDestroyed(this),
        tap(() => this.loadVulnsPage()),
        tap( () => {
          this.total -= this.paginator.pageSize;
        })
      )
      .subscribe();
  }

  loadVulnsPage() {
    this.dataSource.loadVulns(
      'ERA Home Security Ltd',
      '',
      'asc',
      this.paginator.pageIndex,
      this.paginator.pageSize);
  }

  getDisplayedColumns() {
    return this.displayColumns
      .filter(cd => !cd.hidden)
      .map(cd => cd.name);
  }

  ngOnDestroy(): void {
  }
export class VulnerabilityDataSource implements DataSource<Vulnerability> {

  private vulnerabilitySubject = new BehaviorSubject<Vulnerability[]>([]);
  private loadingSubject = new BehaviorSubject<boolean>(false);
  public loading$ = this.loadingSubject.asObservable();

  constructor(private vulnerabilityDataService: VulnerabilityDataService) {
    this.vulnerabilitySubject.subscribe(res => console.log('vulnerability subject emiiting ', res))
  }

  public thing() {
    return this.vulnerabilitySubject.asObservable()
  }

  connect(collectionViewer: CollectionViewer): Observable<Vulnerability[]> {
    console.log('connect called');
    return this.vulnerabilitySubject.asObservable();
  }

  disconnect(collectionViewer: CollectionViewer): void {
    this.vulnerabilitySubject.complete();
  }

  loadVulns(clientName: string, filter = '',
            sortDirection = 'asc', pageIndex = 0, pageSize = 3) {

    this.vulnerabilityDataService.fetchVulnerabilities(clientName, filter, sortDirection,
      pageIndex, pageSize)
      .pipe(
        catchError(() => of([])),
        map(res => {
          return new JsonConvert().deserializeArray(res, Vulnerability);
        })
      ).subscribe(v => {

      this.vulnerabilitySubject.next(v);
    });

  }
}

The problem is the Connect() is not updating dataSource in my component. It does render 2 pages, the third page is not rendered in the table.

I can see the HTTP calls and this.vulnerabilitySubject.next(v); emitting the next set of values. However, the connect method breaks for some reason and does not update the table beyond after page 2.

Any ideas from anyone? I can't seem to figure this one out.


回答1:


Your VulnerabilityDataSource, has not property data nor filter nor sort...

Really I can't imagine what do you want to reach with your code. If the only you want a mat-table with filter, sort and pagination in server, you can get it only subscribing to filter.valuesChange, paginator.page and sort.sortChange

Imagine you has a service with two functions

 //return and observable with the length of the data
getLength(filter:string)

//return an observable of an array with the data filtered, ordered and take account
//page and pageSize
getData(page:number,
        pageSize:number,
        filter:string,
        sortField:string,
        sortDirection:string)

In ngAfterViewInit you can has some like

  ngAfterViewInit() {
    const getLength = this.filter.valueChanges.pipe(
      startWith(null),
      debounceTime(200),
      switchMap((res: string) => this.dataService.getLength(res)),
      tap((res: number) => {
        this.paginator.firstPage();
        this.total = res;
      })
    );
    const sort = this.sort.sortChange.pipe(
      tap(() => this.paginator.firstPage())
    );
    merge(getLength, sort, this.paginator.page)
      .pipe(
        distinctUntilChanged(),
        tap(_ => (this.isLoadingResults = true)),
        switchMap(res => {
          return this.dataService.getData(
            this.paginator.pageIndex,
            this.paginator.pageSize,
            this.filter.value,
            this.sort.active,
            this.sort.direction
          );
        }),
        tap(_ => (this.isLoadingResults = false))
      )
      .subscribe((res: any[]) => {
        this.dataSource = res;
      });
  }

where

  filter = new FormControl();
  isLoadingResults = false;
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

See that we merge trhee observables: when the formControl that make of "filter" change the value, when change the pagine in paginator and when sort the data

We use pipe(tap) to send to the first page in the last two cases. This is the stackblitz, I hope this can help you



来源:https://stackoverflow.com/questions/63780213/connect-method-datasource-is-not-emitting-all-paginated-rows-for-mattable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!