Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
142 views
in Technique[技术] by (71.8m points)

html - angular mat-table is not refreshing after insert

I want to refresh my angular-material table (mat-table) when i insert a new book. The table is not refrsh automatically, i must refresh the browser for seeing the new book inserted.

Steps to do it

  1. Click to the "Create" button"
  2. Fill all fields in the MatDialog
  3. Click to the "ENVOYER" BUTTON
  4. A new book is inserted in the database

But the table doesn't load the last book inserted automatically.

How can i tell to my booklistcomponent (angular component which shows the mat-table) to add automatically the new book without refresh the page.

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import {MatDialog, MatDialogConfig, MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import { Book } from '../models/book';
import { BookService } from '../services/book.service';
import { BookComponent } from '../book/book.component';
//import { BookComponent } from '../book/book.component';

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

  public pbookList;

  booksResult: Book[] ;

  dataSource;

  searchKey: string;

 // private dialog: MatDialog;

  displayedColumns: string[] = ['titre', 'auteur','isbn', 'date enregistrement', 'date publication', 'actions'];
  // dataSource = new MatTableDataSource<Book>(this.booksResult);
  listData: MatTableDataSource<Book>;

  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;

  constructor(private bookService: BookService, public dialog: MatDialog) { }

  ngOnInit(): void {
    this.chargerLivres();
    this.dataSource = new MatTableDataSource<Book>(this.booksResult);
  }

  applyFilter() {
    this.listData.filter = this.searchKey.trim().toLowerCase();
  }

  chargerLivres(){
    console.log("list des books avant affcihage");
      this.bookService.loadBooks().subscribe(
              (result: Book[]) => {
                console.log("list des books : ",result);
                this.booksResult = result;
                this.listData = new MatTableDataSource(result);
                this.pbookList=result;
                console.log("bookResult : ",this.booksResult);
              },
              error => {
                console.log("Erreur : ",error);
              }
      );
  }

  onCreate() {
    this.bookService.initializeFormGroup();
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = "60%";
    //dialogConfig.width = "350px";
    this.dialog.open(BookComponent,dialogConfig);
  }

}

<div class="container">
    <div fxFlex="60">
        <div class="search-div mr-2">
            <button mat-raised-button (click)="onCreate()">
              <mat-icon>add</mat-icon>Create
            </button>
            <mat-form-field class="ml-2 search-form-field" floatLabel="never">
              <input matInput [(ngModel)]="searchKey" placeholder="Search" autocomplete="off" (keyup)="applyFilter()">
              <button mat-button matSuffix mat-icon-button aria-label="Clear"*ngIf="searchKey"  (click)="onSearchClear()">
                <mat-icon>close</mat-icon>
              </button>
            </mat-form-field>
          </div>
        <div class="mat-elevation-z8">
            <table mat-table [dataSource]="listData">

                
                <ng-container matColumnDef="titre">
                    <th mat-header-cell *matHeaderCellDef> Titre </th>
                    <td mat-cell *matCellDef="let element"> {{element.title}} </td>
                </ng-container>

                <ng-container matColumnDef="auteur">
                    <th mat-header-cell *matHeaderCellDef> Auteur </th>
                    <td mat-cell *matCellDef="let element"> {{element.author}} </td>
                </ng-container>

               
                <ng-container matColumnDef="isbn">
                    <th mat-header-cell *matHeaderCellDef> Isbn </th>
                    <td mat-cell *matCellDef="let element"> {{element.isbn}} </td>
                </ng-container>

                <ng-container matColumnDef="date enregistrement">
                    <th mat-header-cell *matHeaderCellDef> Date enregistrement </th>
                    <td mat-cell *matCellDef="let element"> {{element.registerDate | date:'dd/MM/yyyy'}} </td>
                </ng-container>

                
                <ng-container matColumnDef="date publication">
                    <th mat-header-cell *matHeaderCellDef> Date publication </th>
                    <td mat-cell *matCellDef="let element"> {{element.releaseDate | date:'dd/MM/yyyy'}} </td>
                </ng-container>

                <ng-container matColumnDef="actions">
                    <th mat-header-cell *matHeaderCellDef>Actions</th>
                    <td mat-cell *matCellDef="let row">
                      <button mat-icon-button><mat-icon>launch</mat-icon></button>
                      <button mat-icon-button color="warn"><mat-icon>delete_outline</mat-icon></button>
                    </td>
                </ng-container>

                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
                <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
            </table>

            <mat-paginator [pageSizeOptions]="[5, 10, 20]"></mat-paginator>
        </div>

    </div>
</div>

import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { NgxSpinnerService } from 'ngx-spinner';
import { Book } from '../models/book';
import { BookService } from '../services/book.service';

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

  public book = new Book();

  constructor(public service: BookService, private spinner: NgxSpinnerService,public dialogRef: MatDialogRef<BookComponent>,@Inject(MAT_DIALOG_DATA) public data: any) { }

  ngOnInit(): void {
  }
  onNoClick(): void {
    this.dialogRef.close();
  }
  onSubmit() {
    if (this.service.form.valid) {
      const formValue = this.service.form.value;
      this.book.author = formValue['auteur'];
      this.book.isbn = formValue['isbNum'];
      this.book.category = formValue['categ'];
      this.book.title = formValue['titre'];
      this.book.totalExamplaries = formValue['totExemplaire'];
      var localDate = new Date(formValue['publiDate']);
      if(localDate.getTimezoneOffset() < 0){
          localDate.setMinutes(localDate.getMinutes() - localDate.getTimezoneOffset() );
      }else{
        localDate.setMinutes(localDate.getMinutes() + localDate.getTimezoneOffset() );
      }
      this.book.releaseDate = localDate;
      if (!this.service.form.get('$key').value){
        //Insert the new book
        this.saveNewBook(this.book);
      }
      else {
        this.service.form.reset();
      }
    }
  }

  /**
* Save new book
* @param book
*/
saveNewBook(book: Book){
  this.spinner.show();
  this.service.saveBook(book).subscribe(
          (result: Book) => {
              console.log("Resultat du livre : ",result);
             if(result.id){
                this.spinner.hide();
                 console.log("Le livre a ajoute avec id : ",result.id);
             }
          },
          error => {
               this.spinner.hide();
               console.log("erreur survenue lors de  ajout : ",error);
          }
  );
}

  onClear() {
    this.service.form.reset();
    this.service.initializeFormGroup();
  }

  onClose() {
    this.service.form.reset();
    this.service.initializeFormGroup();
    this.dialogRef.close();
  }

  /**
* Save zone local date to the book releaseDate property : 
*   there is a recognized problem with datepicker @angular/material timezone conversion.
* @param book
*/
setLocalDateToDatePicker(book: Book){
  var localDate = new Date(book.releaseDate);
  if(localDate.getTimezoneOffset() < 0){
      localDate.setMinutes(localDate.getMinutes() - localDate.getTimezoneOffset() );
  }else{
    localDate.setMinutes(localDate.getMinutes() + localDate.getTimezoneOffset() );
  }
  book.releaseDate = localDate;
}

}

<mat-toolbar>
    <span>{{service.form.controls['$key'].value?"Modifier un livre":"Nouveau livre"}}</span>
    <span class="fill-remaining-space"></span>
    <button class="btn-dialog-close ml-auto" mat-stroked-button (click)="onClose()" tabIndex="-1"><mat-icon>clear</mat-icon></button>
  </mat-toolbar>
  <form [formGroup]="service.form" class="normal-form" (submit)="onSubmit()">
    <mat-grid-list cols="2" rowHeight="300px">
      <mat-grid-tile>
        <div class="controles-container">
          <input type="hidden" formControlName="$key">
          <mat-form-field>
            <input formControlName="titre" matInput placeholder="Titre*" >
            <mat-error>Le titre est obligatoire.</mat-error>
          </mat-form-field>
          <mat-form-field>
            <input formControlName="auteur" matInput placeholder="Auteur*" >
            <mat-error>Le nom de l'auteur est obligatoire.</mat-error>
          </mat-form-field>
          <mat-form-field>
            <input formControlName="isbNum" matInput placeholder="Isbn*" >
            <mat-error>L'isbn est obligatoire.</mat-error>
          </mat-form-field>
        </div>
      </mat-grid-tile>
      <mat-grid-tile>
        <div class="controles-container">
          <input type="hidden" value="test" name="test">
          <mat-form-field>
            <input formControlName="totExemplaire" type="number" matInput placeholder="Total Exemplaires*" >
            <mat-error>Le nombre d'exemplaire est obligatoire.</mat-error>
          </mat-form-field>
          <mat-form-field>
            <input formControlName="publiDate" [matDatepicker]="myDatepicker" matInput placeholder="Date publication*" >
            <mat-datepicker-toggle matSuffix [for] = "myDatepicker" plac

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The issue is very similar to something that I have explained in this answer in layman's terms. Please go through this first, so that you'll know what to do differently here.

Although your book.component is responsible for adding new book and booklist.component is responsible for displaying all books, we need to refresh booklist from book but with a little TWIST.

I observed that you add new book via book.component and trigger service.saveBook(), and you trigger service.loadBooks() via booklist.component to load books data. You already have a service book.service.ts common to both. Good. The below steps are based on this assumption, kindly adjust them if assumps are misplaced.

WAY 1 - SIMPLER

Steps:

  1. When you trigger service.saveBook() from saveNewBook() you need to call Service.sendUpdate(like the one in my answer) and simply send a flag (simple way) on success.

     saveNewBook(book: Book){
     this.service.saveBook(book).subscribe(
           (result: Book) => {
               console.log("Resultat du livre : ",result);
              if(result.id){
                  this.service.sendUpdate('A msg/flag');
                 // rest code same
              }
           },
          //rest code same
          }
    
  2. In the book.service, Once the sendUpdate is triggered, it will feed the value(lets say a flag) in the Subscription and automatically the Subscription calls for the Observers.

  3. The Observer would be in our booklist.component and they will subscribe to it. It means that the booklist component would automatically know that a new book is added.

  4. Toppings on the Icecream- Now while subscribing to it, you just need to trigger your chargerLivres() - which seems to be responsible for fetching.

     export class BooklistComponent implements OnDestroy {
     messageReceived: any;
     private subscriptionName: Subscription; //important to create a subscription
    
     constructor(pprivate bookService: BookService) {
         // subscribe to sender component messages
         this.subscriptionName= this.bookService.getUpdate().subscribe
          (message => { //message contains the data sent from service
          this.messageReceived = message; //kind of a flag here
          chargerLivres(); //or ngOnInit() whichever responsible for laoding
          });
    

Although the above Way was easy, questions can be raised on loading all books data on just one book addition!!. Hopefully we can tackle that too but with a bit extra work xD

WAY 2 -

  1. When a book is successfully added via saveNewBook(), then trigger sendUpdate and send the result i.e. the details of the new book(and not a flag/msg)
  2. Now when the result is fed into the subscription, then we can receive that book detail in our booklist component by subscribing to it.
  3. In the booklist component, do NOT call the chargerLivres(). Rather add that particular book detail into your existing data (the twist) and your data will refresh.

PS: I appreciate you uploading your file in stackblitz but your backend server is on your localhost xD. Consequently, it was difficult in understanding the api architecture.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...