Reputation: 7765
I am using Angular Material Table that is backed by a plain array as the data source.
this.employees = this.route.snapshot.data.employes; // of type Employee[] resolved using a Resolve guard
this.dataSource = new MatTableDataSource<Employee>(this.employees);
Once rendered initially, I want to add/remove rows from the data table by modifying the 'this.employess' array using method in my component :-
addEmployee(e: Employee){
this.employess.push(e); // I expect the table to have one row added after this.
}
removeEmployee(index : number){
// splice the array at given index & remove one row from data table
}
PROBLEM
The data table rows are not affected when I add remove elements in my array. I found an a blog elaborating same problem but uses a custom data source. Is there any way using plain array ?
Upvotes: 7
Views: 28276
Reputation: 11
I am using Angular 9, Here what i have done
this.dataSource.data.push({
profile:"profile",
skillRequired:"skillRequired"
});
this.dataSource.filter = "";
using filter datatable automatically gets updated
Upvotes: 0
Reputation: 9964
In Latest versions of Angular Material 7/8
You need to call .renderRows() method after pushing new row data
addRowData(row_obj){
var d = new Date();
this.dataSource.push({
id:d.getTime(),
name:row_obj.name
});
this.table.renderRows();
}
deleteRowData(row_obj){
this.dataSource = this.dataSource.filter((value,key)=>{
return value.id != row_obj.id;
});
}
Source Tutorial link
Upvotes: 11
Reputation: 161
The Simplest way is to call _updateChangeSubscription() on your dataSource as you are already using MatTableDataSource
this.dataSource = new MatTableDataSource(this.employees);
Your new modified addEmployee method will become:
addEmployee(e: Employee){
this.employess.push(e); // I expect the table to have one row added after this.
this.dataSource._updateChangeSubscription() // THIS WILL DO
}
Upvotes: 16
Reputation: 1956
The problem is angular/ Mat-table does not detect any modifications to the underlying array after it has been instantiated. Hence, if you choose to add or delete a row you have to explicitly make the table listen to the event or just refresh the tables data. Below is how you would do it.
addEmployee(e: Employee){
this.employess.push(e); // I expect the table to have one row added after this.
this.dataSource.data = this.employees; // this step will refresh the table
}
Same would be the case with your remove method.
Hope this helps.
Upvotes: 3
Reputation: 19288
I'm not sure if this is the best solution, but you could create a subject in which you store your data. Now you can use it just like the blogpost.
public $data: BehaviorSubject<MyDataType[]> = new BehaviorSubject([]);
addEmployee(e: Employee){
this.$data
.first()
.subscribe(data => {
let newData = data.slice();
newData.push(e);
this.$data.next(newData);
}
}
Upvotes: 0
Reputation: 7733
You can create a class EmployeeDataSource
that takes an Observable<Employee[]>
instead of Employee[]
:
import {DataSource} from '@angular/cdk/collections';
import {Observable} from 'rxjs/Observable';
export class EmployeeListDataSource extends DataSource<any> {
constructor(private _employeeList$: Observable<Employee[]>) {
super();
}
connect(): Observable<Employee[]> {
return this._employeeList$;
}
disconnect() {
}
}
Then create your data source by passing an observable :
this.dataSource = new EmployeeListDataSource(yourObservable);
You can find a stackblitz example here.
Upvotes: 1