I am trying to implement a Material Design table in Angular 4 that receives data from a service call. No matter what I try, I cannot get the table to populate even though my service is returning data properly. I do not receive any errors in the console. It appears that the connect() function in the datasource never gets called (as per the traces I placed everywhere) hence my datasource is always empty. I am running material in version 2.0.0-beta.12. I did read that there was a bug in previous versions of material and that's why I included the call to "this._changeDetector.detectChanges();" in my component ngOnInit but it did not help. I also read the question How to use md-table with services in Angular 4 and implemented the recommendations.
After looking through the official doc and lots of threads, here is the code I came up with:
role.component.ts
import { Component, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
import { MatPaginator } from '@angular/material';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { DataSource } from '@angular/cdk/table';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import { RoleService } from '../shared/services/role/role.service';
import { Role } from '../shared/classes/role';
@Component({
selector: 'app-roles',
templateUrl: './role.component.html',
styleUrls: ['./role.component.css']
})
export class RoleComponent implements OnInit {
public displayedColumns = ['role_name', 'tech_stack'];
public roleDatabase = new RoleDatabase(this._roleService);
public roleDatasource: RoleDatasource | null;
@ViewChild(MatPaginator) paginator: MatPaginator;
constructor(private _roleService: RoleService, private _changeDetector: ChangeDetectorRef) { }
ngOnInit() {
this.roleDatasource = new RoleDatasource(this.roleDatabase, this.paginator);
this._changeDetector.detectChanges();
}
}
export class RoleDatabase {
dataChange: BehaviorSubject<Role[]> = new BehaviorSubject<Role[]>([]);
get data(): Role[] { return this.dataChange.value; }
constructor(private _roleService: RoleService) {
this.getAllRoles();
}
getAllRoles() {
this._roleService.getRoles().subscribe( response => {
this.dataChange.next(response);
});
}
}
export class RoleDatasource extends DataSource<any> {
constructor(private _roleDatabase: RoleDatabase, private _paginator: MatPaginator) {
super();
}
connect(): Observable<Role[]> {
const displayDataChanges = [
this._roleDatabase.dataChange,
this._paginator.page
];
return Observable.merge(...displayDataChanges).map(() => {
const data = this._roleDatabase.data.slice();
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
return data.splice(startIndex, this._paginator.pageSize);
})
}
disconnect() { }
}
role.service.ts
import { Injectable } from '@angular/core';
import { Http, Response, URLSearchParams, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import { Role } from '../../classes/role';
@Injectable()
export class RoleService {
private rolesHeaderUrl = '/local/roles';
constructor(private http: Http) { }
getRoles(): Observable<Role[]> {
return this.http.get(this.rolesHeaderUrl)
.map(response => response.json() as Role[])
.catch(this.getError);
}
private getError(error: Response): Observable<any>{
return Observable.throw(error.json() || 'Server Issue');
}
}
and finally the role.component.html:
<mat-card class="title-card">
<mat-card-title class="page-title">Roles</mat-card-title>
</mat-card>
<mat-card>
<mat-table #roletable [dataSource]="roleDataSource">
<ng-container matColumnDef="role_name">
<mat-header-cell *matHeaderCellDef> Role Name </mat-header-cell>
<mat-cell *matCellDef="let role"> {{role.role_name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="tech_stack">
<mat-header-cell *matHeaderCellDef> Technical Stack </mat-header-cell>
<mat-cell *matCellDef="let role"> {{role.tech_stack}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
<mat-paginator #paginator
[length]="roleDatabase.data.length"
[pageIndex]="0"
[pageSize]="25"
[pageSizeOptions]="[5, 10, 25, 100]">
</mat-paginator>
</mat-card>
I must be missing something obvious (hopefully!) at this point... if someone could just find it!!
Thanks for the help!
dda