简体   繁体   中英

how to wait until deletion is complete then reload angular mat table

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

在此处输入图像描述

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.

UPDATE:

My temporary solution is to reload the current router.

app-routing.module.ts

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})],
  exports: [RouterModule]
})

list.component.ts

ngOnInit() {
  this.router.routeReuseStrategy.shouldReuseRoute = () => {
    return false;
  }
}

onDelete(id: string) {
    this.clientService.delete(id).subscribe(response => {
      if (response == 200) {
        this.router.navigate(['/client']);
      }
    });
}

But it will be great if there are other better solutions than this one.

      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();
    });

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM