添加新行

问题描述

(角度8)

我有两个组件addgame和home,在home中,我借助REST API显示了存储在数据库中的所有游戏。

在家庭组件中,通过使用Mat-dialog,我在对话框视图中称为游戏组件。

问题是,如果我在该mat-dialog中添加了游戏,则可以成功添加该游戏,但是只有在手动刷新home组件之后才会在mat-table中更新

我需要在不进行任何手动刷新的情况下更新席子表

注意:我尝试了 ChangeDetectorRef ,触发了 MatPaginator ,并从here得到了所有可能的答案,但没有任何变化

home.component.html

<div class="search-div">
    <button mat-raised-button (click)="onCreateGame()"><mat-icon >add</mat-icon>Create Guest</button>
    <mat-form-field class="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">
    <mat-table [dataSource]="listData">
        <ng-container matColumnDef="gameName">
            <mat-header-cell *matHeaderCellDef>Game Name</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.gameName}}</mat-cell>
        </ng-container>
        <ng-container matColumnDef="gameDate">
            <mat-header-cell *matHeaderCellDef>Game Date</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.gameDate | date}}</mat-cell>
        </ng-container>
        <ng-container matColumnDef="gameVenue">
            <mat-header-cell *matHeaderCellDef>Game Venue</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.gameVenue}}</mat-cell>
        </ng-container>
        <ng-container matColumnDef="homeTeam">
            <mat-header-cell *matHeaderCellDef>Home Team</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.homeTeam}}</mat-cell>
        </ng-container>
        <ng-container matColumnDef="awayTeam">
            <mat-header-cell *matHeaderCellDef>Away Team</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.awayTeam}}</mat-cell>
        </ng-container>
        <ng-container matColumnDef="numberOfGuest">
            <mat-header-cell *matHeaderCellDef>No of Guest</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.numberOfGuest}}</mat-cell>
        </ng-container>
        <ng-container matColumnDef="loading">
            <mat-footer-cell *matFooterCellDef colspan="6">
                Loding data...
            </mat-footer-cell>
        </ng-container>
        <ng-container matColumnDef="noData">
            <mat-footer-cell *matFooterCellDef colspan="6">
                No data.
            </mat-footer-cell>
        </ng-container>
        
        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns:displayedColumns;"></mat-row>

        <mat-footer-row *matFooterRowDef="['loading']" [ngClass]="{'hide': listData!=null}"></mat-footer-row>
        <mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide': !(listData!=null && listData.data.length==0)}"></mat-footer-row>
    </mat-table>
    <mat-paginator [pageSizeOptions]="[5,10,25,100]" pageSize="5" showFirstLastButtons></mat-paginator>

</div>

home.component.ts

import { LoginService } from './../service/login.service';
import { AddgameComponent } from './../addgame/addgame.component';
import { GameService } from './../service/game.service';
import { MatTableDataSource,MatTable } from '@angular/material/table';
import { Component,OnInit,ViewChild,ChangeDetectorRef,AfterContentChecked,OnDestroy } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatDialog,MatDialogConfig } from '@angular/material/dialog';


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

  constructor(public loginService : LoginService,public gameService :GameService,public dialog : MatDialog) { }

  listData : MatTableDataSource<any>;

  @ViewChild(MatPaginator) paginator : MatPaginator

 
  displayedColumns : string[] = ['gameName','gameDate','gameVenue','homeTeam','awayTeam','numberOfGuest'];
  ngOnInit(): void 
  {
    this.starter();

  }

  starter()
  {
    this.gameService.getAllGamesFromremote().subscribe(
      data =>{
        let array = data;
        this.listData = new MatTableDataSource(array);
        this.listData.paginator = this.paginator;
        this.listData.filterPredicate = (data,filter) => (data.gameName.trim().toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1 ||data.homeTeam.trim().toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1 );
      });

  }

  searchKey : string = "";


  onSearchClear()
  {
    this.searchKey = "";
    this.applyFilter();
  }

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

  onCreateGame()
  {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus=true;
    dialogConfig.width="60%";
    this.dialog.open(AddgameComponent,dialogConfig);
  }

}

addgame.component.html

<mat-toolbar>
    <span>Add new Game</span>
    <span class="filler"></span>
    <button class="btn-dialog-close" mat-stroked-button (click)="onClose()" tabindex="-1"><mat-icon>close</mat-icon></button>
</mat-toolbar>

<form class="normal-form" [formGroup]="gameService.gameForm" autocomplete="off" (submit)="onSubmit()">
    <div class="controls-container">
        <mat-form-field>
            <input matInput formControlName="gameName" placeholder="Game Name*">
            <mat-error *ngIf="gameService.gameForm.controls['gameName'].errors?.required">This is Mandatory Field</mat-error>
            <mat-error *ngIf="gameService.gameForm.controls['gameName'].errors?.notUnique">Game name should be Unique</mat-error>
        </mat-form-field>
        <mat-form-field>
            <input matInput formControlName="gameVenue" placeholder="Game Venue*">
            <mat-error>This is Mandatory Field</mat-error>
        </mat-form-field>
        <mat-form-field>
            <input matInput formControlName="homeTeam" placeholder="Home Team*">
            <mat-error>This is Mandatory Field</mat-error>
        </mat-form-field>
        <mat-form-field>
            <input matInput formControlName="awayTeam" placeholder="Away Team*">
            <mat-error>This is Mandatory Field</mat-error>
        </mat-form-field>
        <mat-form-field>
            <input matInput formControlName="gameDate"  [matDatepicker]="picker" placeholder="Game Date*">
            <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
            <mat-datepicker #picker></mat-datepicker>
            <mat-error>This is Mandatory Field</mat-error>
        </mat-form-field>
        <input type="hidden" formControlName="gameName" placeholder="Game Name*">
        <div style="text-align: center;">
            <button mat-raised-button color="primary" type="submit" [disabled]="gameService.gameForm.invalid">Add Game</button>
        </div>
    </div>
</form>

addgame.component.ts

import { Router } from '@angular/router';
import { NotificationService } from './../service/notification.service';
import { GameService } from './../service/game.service';
import { Component,OnInit } from '@angular/core';
import { DatePipe } from '@angular/common';
import { MatDialogRef } from '@angular/material/dialog';

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

  constructor(public gameService : GameService,public notificationService : NotificationService,private datePipe: DatePipe,public  dialogRef : MatDialogRef<AddgameComponent>,public router : Router) { }

  ngOnInit(): void {


  }

  onSubmit()
  {
    this.gameService.addGametoRemote(this.gameService.gameForm.value).subscribe(
      data=>{
        
        this.notificationService.success("Game Added Sucessfully");
        this.gameService.initializeform();
        console.log("Game added");
        this.gameService.gameForm.reset();
        this.onClose();
        

      },error=>{
        this.gameService.gameForm.controls['gameName'].setErrors({"notUnique": true});
        this.notificationService.error("Game name already taken");
        console.log("Error in adding Game")
      }
    )

    
  }

  onClose()
  {
    this.gameService.gameForm.reset();
    this.gameService.initializeform();
    this.dialogRef.close();
  }

}

解决方法

您可以尝试重新调用REST API,以在对话框关闭后再次获取所有游戏。为此,您可以使用以下代码:

 const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus=true;
    dialogConfig.width="60%";
    dialogConfig.data = {somedata: 'data'};
    const dialogId = this.dialog.open(AddgameComponent,dialogConfig);
    const dialogSubmitSubscription = dialogId .componentInstance.onDialogueClose.subscribe(result => {
      if(result) {
          this.starter();
        }
      dialogSubmitSubscription.unsubscribe();
  });

此外,如果动态更改数据后表未更新,则可能需要调用Angular的ngOnChanges Hook。

  ngOnChanges(changes: SimpleChange) {
    if (changes["tableData"]) {
      this.data = new MatTableDataSource(this.tableData);
      if (this.data != undefined) {
        this.data = new MatTableDataSource(this.tableData);
        this.data.sort = this.sort;
      }
      setTimeout(() => {
        this.data.paginator = this.paginator;
        this.data.sort = this.sort;
      });
    }
  }

希望这个答案有助于解决您的问题。

,

下面是我的方法

声明一个可观察的

allGamesFromRemote$ = this.gameService.getAllGamesFromRemote().pipe(
  tap( data =>{ 
    let array = data;
    this.listData = new MatTableDataSource(array);
    this.listData.paginator = this.paginator;
    this.listData.filterPredicate = (data,filter) => 
      (data.gameName.trim().toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1 || data.homeTeam.trim().toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1 );
  });

我们现在需要一种在每次更改时触发可观察对象的方法 为此,我们可以声明两个变量

remoteChangedSubject$ = new BehaviorSubject<any>(true);
remoteChangedAction$ = this.remoteChangedSubject$.asObservable()

接下来将结合两个可观察对象

// Make sure combineLatest to import from 'rxjs'
allGames$ = combineLatest([this.allGamesFromRemote$,this.remoteChangedAction$]).pipe(
  map(([allGames]) => allGames)
)

最后,添加成功后,您将致电

this.remoteChangedSubject$.next(true);

然后在您的html中,使用异步管道将表包装在*ngIf中,以为我们处理订阅

<ng-container *ngIf='allGames$ | async'> 

<!-- Your Table Code Here-->

</ng-container>

这样,只要您调用this.remoteChangedSubject$.next(true);allGames$即可观察,就会重新评估,并启动更改检测

,

鉴于:

数据源:listData

数据源类型:MatTableDataSource

starter() :通过调用 API 填充 listData this.gameService.getAllGamesFromRemote()

dialogConfig,一个 MatDialog :用于输入新的游戏细节

要遵循的步骤:

  1. 获取 newGame 数据作为与 listData 数组中的游戏详细信息匹配的类型的 JSON 对象

  2. 使用;

    将这个新的 Game JSON 对象推送到 DataSource Array 对象中

    this.listData.data.push(新游戏 JSON 对象)

  3. 在 .push() 之后添加以下行

    this.listData.data._updateChangeSubscription();

这将确保新条目立即反映在您的表格中。

注意:

  1. 您可能希望在更新表之前保留新的游戏数据
  2. push() 将新游戏添加到表数组的末尾
  3. 由于您使用的是 MatPaginator,您可能需要重置为首页