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.
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() {}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With