How to use md-table with services in Angular 4
Here's an example of retrieving data through HTTP: https://plnkr.co/edit/mjQbufh7cUynD6qhF5Ap?p=preview
You are missing a piece where GroupDatabase
does not put any data values on the dataChange
stream. It is a BehaviorSubject
that starts with an empty array but you do not put any more data on it. This is why the table is only receiving an empty array.
First, know that ngOnInit
will not be called by Angular since GroupDatabase
is not a directive and is not part of the change detection cycle.
Instead, move this.getAllGroups()
to the constructor of GroupDatabase
. and then subscribe to its result:
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));
}
}
Alternatively, get rid of GroupDatabase altogether and have your CustomDataSource
directly call your 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() {}
}
Helongh
Updated on June 07, 2022Comments
-
Helongh about 2 years
I am quite new in the angular world and i'm trying to use the new md-table component in Angular Material 2 with Angular 4.
I've made a service from an API which retrieves simple arrays of content. Now I'm trying to use this service as a data source for the md-table but I can't find a way to get the data from the service (it always return me an empty array).
Please note that before using md-table, I was using already using the service and it worked normally.
Here is the code for the component :
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() {} }
Here is the code for the 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>
And the concerned service :
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) }
I'm not sure how I should call the service using the datasource, that's why I did it as I was doing before; using the ngOnInit method.
Thanks for you help.
-
Helongh almost 7 yearsThanks for your answer. Indeed this solved my issue, but the doc really i confusing !
-
Tim almost 7 yearsUsing the first method with the GroupDatabase, how/when do you pass in the service? See my question at stackoverflow.com/questions/46456808/… for more specifics on the question and to see what I tried.
-
k.vincent over 6 years@Andrew: I'am following the your example on Plunker which is working fine with
GitHub API
but when I change the URL and add minehttp://localhost:4000/users
, I get following error:ERROR TypeError: t.json(...).map is not a function
. I assume it's affecting this part of code:return result.json().map(issue => {return {....}});
. Any idea what should be fixed there? Thanks. -
carkod almost 6 years@k.vincent that basically means your
t
is basically not formatted properly. Have you tried loggingt
? What type is it?