Home > Software design >  How to Refresh MatTable Data after upload file
How to Refresh MatTable Data after upload file

Time:01-20

enter image description herei'm new in Angular since a week i'm facing an anoying issue that i'cant fix it. After uploading a file in my backend to insert users from a compagny, my MatTable doesn't refresh automatically by itself, I need to reload the page to see users has been added. I've search actually almost everything about this topic but none of them helped me. I have two components (fileUpload and listUser rendered in same route). Even when i'm calling my getUsers() rest api method , nothing change. By advance thank's for the helps and sharing knowledge.

UserService.ts

export class UserService {

  public refreshList$ = new BehaviorSubject<boolean>(true);

  constructor(private http: HttpClient) {}

  getUsers(): Observable<IUsers[]> {
    return this.http
      .get<IUsers[]>(`${BASEURL}/list`)
      .pipe(
        map((users) => {
          console.log(users);
          return users;
        })
      );
  }

  uploadFile(file: File): Observable<HttpEvent<any>> {
    const formData: FormData = new FormData();
    formData.append('file', file);
    return this.http
      .post<HttpEvent<any>>(`${BASEURLL}/upload`, formData, {
        reportProgress: true,
        responseType: 'json'
      });
  }
  

FileUploadComponent.ts

export class FileUploadComponent {

  @Output() emitUpload : EventEmitter<BehaviorSubject<boolean>> = new EventEmitter();

  constructor(private user: UserService) { }

  upload(): void {
    // ignore upload file process..
  
    this.user.refreshList$.next(false); // try to notify upload has been done to call getList()
    this.emitUpload.emit(this.user.refreshList$); // FileUploadComponent.ts is a child of my listComponent.ts
  }

}

ListUserComponent

export class ListUserComponent implements OnInit{ 
  displayedColumns: string[] = ['username', 'lastName', 'firstName'];
  users : IUsers[];
  usersDataSource: MatTableDataSource<IUsers>;
  @ViewChild(MatPaginator) paginator !: MatPaginator;

  constructor(private user: UserService) { }

  ngOnInit() {
    this.getUserList(); // get my users when component is rendered
    console.log(this.user.refreshList$.getValue()); // try to get value of my Behavior
  }

  getUserList() {  
        this.user.getUsers().subscribe(
          (users) => {
          console.log(users);
          this.users = users;
            this.usersDataSource = new MatTableDataSource<IUsers>(copyOf(this.users));
            this.usersDataSource.paginator = this.paginator;
          }, 
          (error) => {
            console.log(error);
          }
       )
  }

  refreshTable(event: BehaviorSubject<boolean>){
    console.log(event.getValue()); // get the new value of behaviorSubject after file upload successfully 
    event.subscribe(() => {
      console.log("Get new value");
      //this.getUserList();
    });
  }

}

ListUserComponent.html

 <div >
  <table mat-table [dataSource]="users">
    <ng-container matColumnDef="username">
     <th mat-header-cell *matHeaderCellDef> Username </th>
     <td mat-cell *matCellDef="let element"> {{ element.username }} </td>
    </ng-container>

    <ng-container matColumnDef="lastName">
      <th mat-header-cell *matHeaderCellDef> Last Name </th>
      <td mat-cell *matCellDef="let element"> {{ element.LastName }} </td>
    </ng-container>
  
    <ng-container matColumnDef="firstName">
      <th mat-header-cell *matHeaderCellDef> firstName </th>
      <td mat-cell *matCellDef="let element"> {{element.firsName}} </td>
    </ng-container> 
  </table> 
  
  <mat-paginator [pageSizeOptions]="[3, 5]" showFirstLastButtons> </mat- 
  paginator> 
 </div>

   <app-FileUpload (emitUpload)="refreshTable($event)"></app-FileUpload>

CodePudding user response:

as of how Material Tables works, you need to inform the table that something has changed (for performance reasons) this.table.renderRows(); see example: https://material.angular.io/components/table/examples#table-dynamic-array-data

CodePudding user response:

For those who got the same problem, i finally found a solution. Add a short timer before calling the list. Bellow the way it looks like :

  1. Add add a Subject and an Observable in your service to notify when there some change

UserService.ts

  private _refresh$ = new Subject<any>();

  get refresh$(){
    return this._refresh$; // Will push value when any changes happend
  }

  listen(): Observable<any> {
    return this._refresh$.asObservable(); // Will listen for the value that was pushed
  }
  1. From method you need to perform , push a value using your Subject created in your Service

FileUpload.component.ts


upload(){
  //process to upload file 
  this.etudiant.refresh$.next('uploaded'); // When the file is uploaded push a value by using your Subject created in your Service.
}
  
  1. From another method, listen the value that has been pushed by your subject and add a short timer before calling your refreshed list

ListUser.component.ts

 constructor(private user: UserService) { }
 ngOnInit() {
    
    /* From your service, call your listen method created previously, responsible 
    to get the value pushed by the "_refresh$". Then add a timer (Ex: 500ms) before 
    calling your list */
    this.user.listen().pipe(debounceTime(500)).subscribe(() => {
         this.getUsers();
    });
  }
  // When we finish with your Subject, will unsubscribe for performance reason (Release memory space) 
  ngOnDestroy() {
    this.user.refresh$.unsubscribe();
  }

  

Hopefully it will help. If someone got a better solution let me know, Thank's by advance.

  • Related