Home > Software engineering >  how to wait until deletion is complete then reload angular mat table
how to wait until deletion is complete then reload angular mat table

Time:12-22

I have a mat table in my angular project just like below:

enter image description here

The data is fetched from server using rest API. The server side is using nodejs and sequelize. When I click the delete button, I want my mat table to refresh with new data. But unfortunately, the refresh data is loaded before the delete is completed, so it looks as if the delete button is not functioning.

Here is my code:

list.component.ts

import {AfterViewInit, ChangeDetectorRef, Component, ViewChild} from '@angular/core';
import {MatPaginator, PageEvent} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
import {MatTableDataSource} from '@angular/material/table';
import { Title } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { ClientService } from 'src/app/core/services/client.service';
import { MainService } from 'src/app/core/services/main.service';
import { Client } from 'src/app/models/client.model';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements AfterViewInit {

  clients: Client[];

  displayedColumns: string[] = ['client_name', 'client_address', 'client_home_phone', 'client_mobile_phone', 'client_status', 'buttons'];
  dataSource: MatTableDataSource<Client>;

  length = 0;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor(private changeDetectorRefs: ChangeDetectorRef, private router: Router, private titleService: Title, private mainService: MainService, private clientService: ClientService) {
    this.titleService.setTitle('Clients');
    this.mainService.setPageTitle('Clients');
    this.mainService.setButtonToolbar([
      {
        'url': 'create',
        'icon': 'add',
        'color': 'primary'
      },
    ]);

    this.clientService.list(25, 0).subscribe(clients => {
      this.clients = clients.data;
      this.dataSource = new MatTableDataSource(this.clients);
      this.length = clients.count;
      this.dataSource.paginator = this.paginator;
      this.dataSource.sort = this.sort;
    });
  }

  ngAfterViewInit() {

  }

  onChangedPage(pageData: PageEvent) {
    this.clientService.list(pageData.pageSize, pageData.pageIndex * pageData.pageSize).subscribe(clients => {
      this.clients = clients.data;
      this.dataSource = new MatTableDataSource(this.clients);
      this.length = clients.count;
      this.dataSource.sort = this.sort;
    });
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.clientService.list(this.paginator.pageSize, 0, filterValue).subscribe(clients => {
      this.clients = clients.data;
      this.dataSource = new MatTableDataSource(this.clients);
      this.length = clients.count;
      this.dataSource.sort = this.sort;
    });
  }

  onUpdate(id: String) {
    this.router.navigate(['/client/update/' id]);
  }

  onDelete(id: string) {
    this.clientService.delete(id).subscribe(response => {
      if (response == 200) {
        this.clientService.list(this.paginator.pageSize, 0).subscribe(clients => {
          this.clients = clients.data;
          this.dataSource = new MatTableDataSource(this.clients);
          this.length = clients.count;
          this.dataSource.sort = this.sort;

          this.changeDetectorRefs.detectChanges();
        });
      }
    });
  }

}

client.service.ts

import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { map } from "rxjs/operators";
import { Client } from "src/app/models/client.model";
import { MainService } from 'src/app/core/services/main.service';

@Injectable()
export class ClientService {

  constructor(private http: HttpClient, private mainService: MainService) {}

  list(limit: number, offset: number, filter?: string) {
    let queryParams = '?limit=' limit '&offset=' offset;
    if (filter) {
      queryParams  = '&filter=' filter;
    }
    return this.http
    .get(this.mainService.getbaseApiUrl() "client/list"   queryParams)
    .pipe(map(responseData => {
      const clientArray = [...responseData['rows']];

      return {data: clientArray, count: responseData['count']};
    }));
  }

  get(id: string) {
    return this.http
      .get(this.mainService.getbaseApiUrl() "client/one/" id);
  }

  add(client: Client) {
    return this.http
      .post(this.mainService.getbaseApiUrl() 'client/add', client, {
        headers: new HttpHeaders({
          // 'Origin': '*',
          //'Access-Control-Allow-Origin': '*',
          //'Access-Control-Allow-Credentials': 'true',
          'Content-Type':  'application/json',
        })
      });
  }

  update(client: Client) {
    return this.http
      .post(this.mainService.getbaseApiUrl() 'client/edit', client, {
        headers: new HttpHeaders({
          // 'Access-Control-Allow-Origin': '*',
          // 'Access-Control-Allow-Credentials': 'true',
          'Content-Type':  'application/json',
        })
      });
  }

  delete(id: string) {
    return this.http.delete(this.mainService.getbaseApiUrl() 'client/delete/' id);
  }
}

I'm new to Angular and this may look simple, but I couldn't think of any solution. Is there any way for Angular to wait until the deletion is completed then refresh? The temporary solution is to use setTimeout so the mat table will refresh after waiting for X seconds, but I don't think that's a clean solution.

Please help.

CodePudding user response:

      onDelete(id: string) {
this.clientService.delete(id)
.pipe(switchMap(() => this.clientService.list(this.paginator.pageSize, 0)
.subscribe(clients => {
      this.clients = clients.data;
      this.dataSource = new MatTableDataSource(this.clients);
      this.length = clients.count;
      this.dataSource.sort = this.sort;

      this.changeDetectorRefs.detectChanges();
    });

CodePudding user response:

Let's start from the declaration

export class ListComponent implements AfterViewInit {

 dataSource: MatTableDataSource<Client>;

Make it into,

export class ListComponent implements AfterViewInit {
    
     dataSource: MatTableDataSource<Client> = new MatTableDataSource<Client>();

You create the dataSource once and then you update only the data it contains not the complete dataSource.

Then everywhere in your code where you refresh your table please replace the following that you have

  this.clients = clients.data;
  this.dataSource = new MatTableDataSource(this.clients);
  this.length = clients.count;
  this.dataSource.sort = this.sort;

with this to update only the data of the table.

  this.dataSource.data = clients.data;

Angular will be able to identify when the data have changed and refresh the data appearing for the MatTable.

  • Related