Implementing AngularMaterial Table with sorting headers I'm getting this Error in console:
ERROR TypeError: Cannot set property 'sort' of undefined at
and this Error in Terminal:
error TS2740: Type 'MatTableDataSource' is missing the following properties from type 'Employee[]': length, pop, push, concat, and 24 more.
error TS2322: Type 'MatSort' is not assignable to type '(compareFn?: (a: Employee, b: Employee) => number) => Employee[]'.
Type 'MatSort' provides no match for the signature '(compareFn?: (a: Employee, b: Employee) => number): Employee[]'.
I cannot get what it wants from me. I would appreciate any hints!
I've used the code from AngularMaterial Documentation except for an interface for Data. Can this be an issue?
EmployeeListComponent
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatSort, MatTableDataSource } from '@angular/material';
import { AngularFirestore } from '@angular/fire/firestore';
import { EmployeeService } from '../shared/employee.service';
import { Employee } from '../shared/employee';
@Component({
selector: 'app-employee-list',
templateUrl: './employee-list.component.html',
styleUrls: ['./employee-list.component.scss']
})
export class EmployeeListComponent implements OnInit {
displayedColumns: string[] = ['fullname', 'position', 'mobile'];
dataSource;
@ViewChild(MatSort) sort: MatSort;
constructor(private service: EmployeeService) { }
ngOnInit() {
this.service.getEmployees().subscribe(employees => {
this.dataSource = new MatTableDataSource(employees);
console.log(this.dataSource);
});
this.dataSource.sort = this.sort;
}
}
EmployeeList HTML
<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="fullname">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Full Name </th>
<td mat-cell *matCellDef="let element"> {{element.fullname}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Position </th>
<td mat-cell *matCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="mobile">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Mobile </th>
<td mat-cell *matCellDef="let element"> {{element.mobile}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
EmployeeService
getEmployees() {
return this.firestore.collection<Employee>('employees')
.snapshotChanges()
.pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data } as Employee;
})
)
);
}
Employee Class
export class Employee {
id: string;
fullname: string;
empCode: string;
position: string;
mobile: string;
}
You are trying to access data from outside the subscription, it should be inside.
After this you will run into trouble with this.sort
being undefined in within the ngOnInit
hook, this occurs because you are trying to access a HTMLelement that has not yet been draw. (MatSort)
There is a lifecycle hook you can use to ensure that the view is ready to be accessed by the @ViewChild, this is ngAfterViewInit, only is only fired when the HTML is drawn.
Try structuring like so.
import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { MatSort, MatTableDataSource } from '@angular/material';
import { AngularFirestore } from '@angular/fire/firestore';
import { EmployeeService } from '../shared/employee.service';
import { Employee } from '../shared/employee';
@Component({
selector: 'app-employee-list',
templateUrl: './employee-list.component.html',
styleUrls: ['./employee-list.component.scss']
})
export class EmployeeListComponent implements AfterViewInit{
displayedColumns: string[] = ['fullname', 'position', 'mobile'];
dataSource;
@ViewChild(MatSort) sort: MatSort;
constructor(private service: EmployeeService) { }
ngAfterViewInit(): void
{
this.service.getEmployees().subscribe(employees => {
this.dataSource = new MatTableDataSource(employees);
if (this.sort) // check it is defined.
{
this.dataSource.sort = this.sort;
}
});
}
}
Documentation AfterViewInit Lifecycle // More details.