Kumar Sambhav
Kumar Sambhav

Reputation: 7765

Angular Material Table | Add Remove rows at runtime

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

Answers (6)

Tushar Adlakha
Tushar Adlakha

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

Code Spy
Code Spy

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

enter image description here

Upvotes: 11

Arun Sharma
Arun Sharma

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

rgantla
rgantla

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

Robin Dijkhof
Robin Dijkhof

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

ibenjelloun
ibenjelloun

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

Related Questions