Как использовать md-таблицу с услугами в Angular 4

Я совершенно новый в мире angular, и я пытаюсь использовать новый компонент md-table в angular Материал 2 с angular 4.

Я сделал сервис из API, который извлекает простые массивы контента. Теперь я пытаюсь использовать эту службу в качестве источника данных для md-таблицы, но я не могу найти способ получить данные из службы (она всегда возвращает мне пустой массив).

Обратите внимание, что перед использованием md-таблицы я уже использовал эту службу, и она работала нормально.

Вот код для компонента:

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.

Спасибо за помощь.

Ответ 1

Вот пример извлечения данных через 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() {}
}