【问题标题】:Creating datasource for nested object in Angular 8在 Angular 8 中为嵌套对象创建数据源
【发布时间】:2019-12-24 10:01:03
【问题描述】:

我正在为一个项目尝试使用 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>

【问题讨论】:

  • 请提供 Stackblitz 示例。
  • 您能否添加更多资源来演示如何使用total/pageSize/pageIndex 属性?我回答了错误,但我不明白您如何使用这些属性。
  • 你不需要扩展数据源,就这样dataSource = new MatTableDataSource();
  • @ValeriyKatkov 这些字段将用于控制分页器,因为响应将被分页和/或过滤。
  • @NavruzbekNoraliev 如果能解决问题,我会尝试并分享。如果我不扩展,我如何使用数据源的连接和断开功能。你能分享一些这种实现的例子吗?

标签: angular typescript angular-material angular8


【解决方案1】:

这是因为 DataSource.connect() should return 是一个发出数据数组的 observable。因此,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)
    );
  }

  ...
}

Here is官方CDK表示例,希望对你有所帮助。 stackblitz 版本也可用。

更新:

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

table-basic-example.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
    });
  }
}

table-basic-example.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>

【讨论】:

  • connect 函数中,您将返回Sample[] 的可观察数组,但我的实际响应将不包含样本数组,而是包含Samples 类型的单个响应。其中的接口在问题中定义。
  • stckblitz 示例也使用了ELEMENT_DATA 的简单对象,但我在这里处理的数据实际上是一个包装对象,例如ELEMENTS_DATA,其中ELEMENT_DATA 作为其属性/字段之一.
  • @pkimtani DataSource 旨在返回一个可观察对象,该可观察对象发出一组行数据,并且不能发出任何其他内容。问题不在于如何强制 DataSource 发出 Samples 实例,而在于您打算如何使用 Samples 类。如果您想实现分页,请查看MatTableDataSource。如果你仍然想使用你的Samples,请添加一个代码示例,它使用这个类,因为很难理解它是如何使用的。
  • 是的,我知道它只能发出一个数据数组,但我想发出对象。我已经用组件实现部分更新了我的问题,如果这就是你要问的。
  • @pkimtani 谢谢,在您的情况下没有必要使用 DataSource 类。我在答案中添加了一个示例。
猜你喜欢
  • 1970-01-01
  • 2017-02-07
  • 2019-01-04
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多