1

我正在为一个项目尝试使用 Angular,但我一直在为我的 MatTable 创建一个数据源。

我正在使用的 API 发送如下响应:

{
    data: [], //array of objects for samples
    total: 100, //total number of samples found
    pageSize: 10,
    pageIndex: 0
}

我的样本模型是:

//Model for a single sample
export class Sample {
    id: number;
    name: string;
}

//a plural namespace is used for multiple samples returned from API
export class Samples {
    samples: Sample[],
    total: number;
    pageSize: number;
    pageIndex: number;
}

// a const in case no samples were found
export const NO_SAMPLES {
    total: 0,
    pageIndex: 0,
    pageSize: 0,
    samples: []
}

现在,当我尝试将其与如下数据源集成时:

... //required imports
export class SamplesDataSource extends DataSource<Samples> {

private samplesSubject = new BehaviorSubject<Samples>(NO_SAMPLES);

public constructor(private samplesService: SamplesService) {
    super();
}

//this is where the error (described below) is showing
connect(collectionViewer: CollectionViewer): Observable<Samples> {
    return this.samplesSubject.asObservable();
}

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

getSamples() {
    this.samplesService.getSamples().pipe(
        catchError(err => {
            return of([]);
        })
    ).subscribe(
        samples => this.samplesSubject.next(samples)
    );

}

}

但它向我显示错误消息:

src/app/shared/data-sources/samples-data-source.ts(20,5) 中的错误:错误 TS2416:“SamplesDataSource”类型中的属性“连接”不可分配给基本类型“数据源”中的相同属性

我该如何处理这种情况。

请注意,我需要保留totalpageSizepageIndex让我的分页器与后端的分页器保持一致。

提前致谢。

编辑

应用组件.ts

    ... //required imports
export class AlertCasesComponent implements OnInit {
  ...

  samplesTableColumns: string[] = ['sampleId', 'sample'];
  samplesTablePageSizes: number[] = [10, 20, 50, 100];
  samplesDataSource: SamplesDataSource;

  ...

  constructor(samplesService: SamplesService) {
    ...
  }

  ngOnInit(): void {
      this.samplesDataSource = new SamplesDataSource(this.samplesService);
      this.samplesDataSource.getSamples();
      ...
  }

  ...

}

应用组件.html

<mat-table class="..." [dataSource]="samplesDataSource.samples">

    .... //rows and columns implementations

</mat-table>

<mat-paginator [length]="samplesDataSource.total" pageIndex="0" [pageSize]="samplesDataSource.pageSize" [pageSizeOptions]="samplesTablePageSizes" showFirstLastButtons></mat-paginator>
4

1 回答 1

3

这是因为DataSource.connect() 应该返回一个发出数据数组的可观察对象。因此, SamplesDataSource 应该返回样本数组,例如:

export class SamplesDataSource extends DataSource<Sample> {
  private samplesSubject = new BehaviorSubject<Samples>(NO_SAMPLES);

  connect(collectionViewer: CollectionViewer): Observable<Sample[]> {
    return this.samplesSubject.asObservable().pipe(
      map(samples => samples.samples)
    );
  }

  ...
}

这是官方的CDK表示例,希望对您有所帮助。stackblitz版本也可用。

更新:

在您的情况下不必使用DataSource类,您可以使用样本数组作为数据源。我创建了stackblitz 示例

表基本示例.ts

import { Component, Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { switchMap, delay } from 'rxjs/operators';
import { PageEvent } from '@angular/material/paginator';

export interface Sample {
  id: number;
  name: string;
}

export interface Samples {
  samples: Sample[];
  total: number;
  pageSize: number;
  pageIndex: number;
}

const ELEMENT_DATA: Sample[] = [
  {id: 1, name: 'Hydrogen'},
  {id: 2, name: 'Helium'},
  {id: 3, name: 'Lithium'},
  {id: 4, name: 'Beryllium'},
  {id: 5, name: 'Boron'},
  {id: 6, name: 'Carbon'},
  {id: 7, name: 'Nitrogen'},
  {id: 8, name: 'Oxygen'},
  {id: 9, name: 'Fluorine'},
  {id: 10, name: 'Neon'}
];

@Injectable()
export class SamplesService {
  getSamples(pageIndex: number, pageSize: number): Observable<Samples> {
    const start = pageIndex * pageSize;
    const samples = ELEMENT_DATA.slice(start, start + pageSize);
    return of<Samples>({
      samples: samples,
      pageIndex: pageIndex,
      pageSize: pageSize,
      total: ELEMENT_DATA.length
    }).pipe(
      delay(500)
    );
  }
}

@Component({
  selector: 'table-basic-example',
  templateUrl: 'table-basic-example.html',
  styleUrls: ['table-basic-example.css'],
  providers: [ SamplesService ]
})
export class TableBasicExample {
  readonly displayedColumns: string[] = ['id', 'name'];
  readonly page$ = new BehaviorSubject({
    index: 0,
    size: 4
  });

  samples: Samples = {
    total: 0,
    pageIndex: 0,
    pageSize: 0,
    samples: []
  };

  constructor(
    private readonly samplesService: SamplesService
  ) {
    this.page$.pipe(
      switchMap(page => {
          return this.samplesService.getSamples(page.index, page.size);
      })
    ).subscribe(samples => {
      this.samples = samples;
    });
  }

  onPageChanged(event: PageEvent) {
    this.page$.next({
      index: event.pageIndex,
      size: event.pageSize
    });
  }
}

表基本示例.html

<table mat-table [dataSource]="samples.samples" class="mat-elevation-z8">
  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef> No. </th>
    <td mat-cell *matCellDef="let element"> {{element.id}} </td>
  </ng-container>

  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef> Name </th>
    <td mat-cell *matCellDef="let element"> {{element.name}} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

<mat-paginator
  [length]="samples.total"
  pageIndex="pageIndex$.value"
  [pageSize]="samples.pageSize"
  [pageSizeOptions]="[4, 9]"
  showFirstLastButtons
  (page)="onPageChanged($event)"></mat-paginator>
于 2019-08-21T08:26:31.097 回答