问题 如何在Angular 4中使用带有服务的md-table


我在角度世界中相当新,我试图在Angular Material 2中使用Angular 4中的新md-table组件。

我从API中提取了一个服务,用于检索简单的内容数组。 现在我正在尝试将此服务用作md-table的数据源,但我找不到从服务获取数据的方法(它总是返回一个空数组)。

请注意,在使用md-table之前,我正在使用该服务并且它正常工作。

以下是组件的代码:

import { Component, OnInit, ViewChild } from '@angular/core';
import {DataSource} from '@angular/cdk';
import {MdPaginator} from '@angular/material';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';

import { GroupService } from '../shared/group.service';
import { Group } from '../shared/group';

@Component({
  selector: 'app-group-list',
  templateUrl: './group-list.component.html',
  styleUrls: ['./group-list.component.css'],
  providers: [GroupService]
})
export class GroupListComponent implements OnInit{

  public DisplayedColumns = ['name', 'email', 'directMembersCount'];
  public groupDatabase = new GroupDatabase();
  public dataSource : CustomDataSource | any;

  @ViewChild(MdPaginator) paginator : MdPaginator;

  constructor() {}

  ngOnInit() {
    this.dataSource = new CustomDataSource(this.groupDatabase, this.paginator);
    console.log(this.dataSource);
  }

}

export class GroupDatabase implements OnInit {

  public dataChange: BehaviorSubject<Group[]> = new BehaviorSubject<Group[]>([]);
  get data(): Group[] { return this.dataChange.value }

  private _groupService : GroupService

  private getAllGroups(){
    return this._groupService
      .getAllGroups();
  }

  constructor (){}

  ngOnInit() {
      this.getAllGroups();
      console.log(this.getAllGroups());
  }
}

export class CustomDataSource extends DataSource<any> {

  constructor(private _groupDatabase = new GroupDatabase(), private _paginator: MdPaginator){
    super();
  }

  connect(): Observable<Group[]> {
    const displayDataChanges = [
      this._groupDatabase.dataChange,
      this._paginator.page
    ];
    return Observable.merge(...displayDataChanges).map(() => {
      const data = this._groupDatabase.data.slice();
      console.log(data);

      const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
      return data.splice(startIndex, this._paginator.pageSize);
    })
  }

  disconnect() {}
}

这是HTML的代码:

<md-table #table [dataSource]="dataSource">

  <ng-container *cdkColumnDef="name">
    <md-header-cell *cdkCellDef>Nom</md-header-cell>
    <md-cell *cdkCellDef="let row"> {{row.name}} </md-cell>
  </ng-container>

  <ng-container *cdkColumnDef="email">
    <md-header-cell *cdkCellDef>Email</md-header-cell>
    <md-cell *cdkCellDef="let row"> {{row.email}} </md-cell>
  </ng-container>

  <ng-container *cdkColumnDef="directMembersCount">
    <md-header-cell *cdkCellDef>Nombre de membres</md-header-cell>
    <md-cell *cdkCellDef="let row"> {{row.directMembersCount}} </md-cell>
  </ng-container>

  <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
  <md-row *cdkRowDef="let row; columns: DisplayedColumns;"></md-row>

</md-table>

<md-paginator #paginator
              [length]="groupDatabase.data.length"
              [pageIndex]="0"
              [pageSize]="25"
              [pageSizeOptions]="[5, 10, 25, 100]">
</md-paginator>

和有关的服务:

private groupApiUrl: string;
  private groupsApiUrl: string;
  private headers: Headers;
  constructor(public http:Http, private config: Config) {
    this.groupApiUrl = config.serverWithApi + "group";
    this.groupsApiUrl = config.serverWithApi + "groups";

    this.headers = new Headers();
    this.headers.append('Content-Type', 'application/json');
    this.headers.append('Accept', 'application/json');
  }

  public getAllGroups = (): Observable<Group[]> => {
    return this.http.get(this.groupsApiUrl)
      .map((response: Response) => <Group[]>response.json())
      .catch(this.handleError)
  }

我不确定如何使用数据源来调用服务,这就是我之前做过的原因;使用ngOnInit方法。

谢谢你的帮助。


7078
2017-07-10 14:08


起源

看起来我不是唯一想知道这个!有关该问题已发布在角度回购上: #5670 - Helongh
在angular.io网站上似乎没有专门针对DataSource的任何文档,只有在讨论其他主题时才会引用它,例如cdk表。我正在坚持的部分是在用户执行搜索后填充DataSource。 - Wallace Howery


答案:


以下是通过HTTP检索数据的示例: https://plnkr.co/edit/mjQbufh7cUynD6qhF5Ap?p=preview


你错过了一块 GroupDatabase 不会在上面放任何数据值 dataChange 流。它是一个 BehaviorSubject 以空数组开头,但不再添加任何数据。这就是表只接收空数组的原因。

首先,要知道 ngOnInit 因此,Angular不会调用它 GroupDatabase 不是指令,也不是变更检测周期的一部分。

相反,移动 this.getAllGroups() 到的构造函数 GroupDatabase。然后订阅其结果:

export class GroupDatabase {
  public dataChange: BehaviorSubject<Group[]> = new BehaviorSubject<Group[]>([]);
  get data(): Group[] { return this.dataChange.value }

  constructor(groupService: GroupService) {
    groupService.getAllGroups().subscribe(data => this.dataChange.next(data));
  }
}

或者,完全摆脱GroupDatabase并拥有你的 CustomDataSource 直接调用您的GroupService。

export class CustomDataSource extends DataSource<Group> {

  constructor(
      private _groupService: GroupService, 
      private _paginator: MdPaginator) { }

  connect(): Observable<Group[]> {
    const displayDataChanges = [
      this._groupService.getAllGroups(),
      this._paginator.page
    ];

    return Observable.merge(...displayDataChanges).map((data, page) => {
      const clonedData = data.slice();

      const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
      return data.splice(startIndex, this._paginator.pageSize);
    })
  }

  disconnect() {}
}

14
2017-07-14 00:57



感谢您的回答。确实这解决了我的问题,但是文档确实令人困惑! - Helongh
将第一种方法与GroupDatabase一起使用,您如何/何时传递服务?看看我的问题 stackoverflow.com/questions/46456808/... 有关问题的更多细节,看看我尝试了什么。 - Tim
@Andrew:我跟随你在Plunker的例子,这个例子很好用 GitHub API 但是当我更改URL并添加我的 http://localhost:4000/users,我得到以下错误: ERROR TypeError: t.json(...).map is not a function。我认为它影响了这部分代码: return result.json().map(issue => {return {....}});。知道应该修复什么吗?谢谢。 - k.vincent
@ k.vincent那基本上意味着你的 t 基本上格式不正确。你有没有尝试过登录 t?它是什么类型的? - carkod