0

我在关闭函数matDialog中的 Angular Material 时遇到问题。ngDoCheck()

编辑: 这里的 StackBlitz

解释 :

在我的主页上,我有一个按钮,可以打开一个matDialog将数据提取或不提取到Excel文件中的按钮。在我的matDialog中,我有两个按钮。一个关闭matDialog另一个启动功能extractWallet(),恢复数据库中的数据。

在这个函数中,我使用waitExtraction变量禁用我的按钮,并禁用关闭,matDialog直到提取完成。

我的loadInvoiceExtractionXXX()方法允许我恢复我的数据库数据,一旦接收到数据, completedExtraction设置[false, false, false]为设置为true对应于函数的索引(0、1 或 2)。

在我ngOnInit()的数据中,数据是通过 an 接收Observer并保存在局部变量中的。因此在执行loadInvoiceExtractionXXX()in之后接收到新数据extractWallet()

我的问题发生在这里。我有一个ngDoCheck()函数可以检查何时收到所有三个数据this.completedExtraction=[true, true, true]。我的Excel文件创建良好并上传到浏览器。提取现已完成,我现在想matDialogthis.dialogRef.close().

但显示以下错误: 在此处输入图像描述

错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。

以前的值:'@dialogContainer: enter'。当前值:“@dialogContainer:退出”。

我试图关闭我matDialog的 in ngAfterViewChecked(),但显示相同的错误。如果有人有解决方案让我matDialog在提取后关闭我的,我会感兴趣的。

我把我的代码交给你了:

export class ExtractWalletComponent implements OnInit, DoCheck, OnDestroy {

  private subscription$: Subscription = new Subscription();

  selectedWallet: Wallet;
  waitExtraction: boolean;
  completedExtraction: boolean[];

  invoiceProduct: InvoiceExtractionProduct[];
  invoiceSupport: InvoiceExtractionSupport[];
  invoiceTraining: InvoiceExtractionTraining[];

  constructor(public dialogRef: MatDialogRef<ExtractWalletComponent>,
              public storeWallets: WalletsComponentStore,
              public snackBar: MatSnackBar) { }

  ngOnInit(): void {
    this.waitExtraction = false;
    this.completedExtraction = [false, false, false];

    this.subscription$.add(this.storeWallets.selectedWallet$.subscribe(wallet => this.selectedWallet = wallet));
    this.subscription$.add(this.storeWallets.invoiceExtractionProduct$.subscribe(invoiceProduct => this.invoiceProduct = invoiceProduct));
    this.subscription$.add(this.storeWallets.invoiceExtractionSupport$.subscribe(invoiceSupport => this.invoiceSupport = invoiceSupport));
    this.subscription$.add(this.storeWallets.invoiceExtractionTraining$.subscribe(invoiceTraining => this.invoiceTraining = invoiceTraining));
  }

  ngDoCheck(): void {
    if(this.completedExtraction[0] == true && this.completedExtraction[1] == true && this.completedExtraction[2] == true) {
      this.completedExtraction[0] = false;
      this.completedExtraction[1] = false;
      this.completedExtraction[2] = false;
      this.dialogRef.disableClose = false;

      const wb: XLSX.WorkBook = XLSX.utils.book_new();
      const ws1: XLSX.WorkSheet = XLSX.utils.json_to_sheet(this.invoiceProduct);
      const ws2: XLSX.WorkSheet = XLSX.utils.json_to_sheet(this.invoiceSupport);
      const ws3: XLSX.WorkSheet = XLSX.utils.json_to_sheet(this.invoiceTraining);

      XLSX.writeFile(wb, this.selectedWallet.user.num_seller + '_' + this.selectedWallet.period.month +
                          '_' + this.selectedWallet.period.year + '_' + this.selectedWallet.id + '.xlsx');

      this.dialogRef.close(); //<-- ERROR
    }
  }

  ngOnDestroy(): void {
    this.subscription$.unsubscribe();
    this.storeWallets.clearExtraction();
  }

  extractWallet(): void {
    this.waitExtraction = true;
    this.dialogRef.disableClose = true;
    this.snackBar.open('Extraction en cours', 'OK', { duration: 5000 });

    this.storeWallets.loadInvoiceExtractionProduct(this.selectedWallet).subscribe(
      res => {
        if(res) { this.completedExtraction[0] = true;}
      },
      err => { console.error(err); this.dialogRef.close(); this.snackBar.open('Echec de l\'extraction', 'OK', { duration: 2000 }); }
    );

    this.storeWallets.loadInvoiceExtractionSupport(this.selectedWallet).subscribe(
      res => {
        if(res) { this.completedExtraction[1] = true; }
      },
      err => { console.error(err); this.dialogRef.close(); this.snackBar.open('Echec de l\'extraction', 'OK', { duration: 2000 }); }
    );

    this.storeWallets.loadInvoiceExtractionTraining(this.selectedWallet).subscribe(
      res => {
        if(res) { this.completedExtraction[2] = true; }
      },
      err => { console.error(err); this.dialogRef.close(); this.snackBar.open('Echec de l\'extraction', 'OK', { duration: 2000 }); }
    );
  }
}

预先感谢您的帮助。

PS:对不起我的英语(谷歌翻译)。

4

1 回答 1

1

好吧,问题正是它告诉您的:您在更改检测周期中更改了某些内容。您需要将更改放在循环之外,例如:

ngDoCheck(): void {
   if(this.completedExtraction[0] == true && this.completedExtraction[1] == true && this.completedExtraction[2] == true) {
      // omitted

      // Run after change detection
      setTimeout(() => this.dialogRef.close());

   }
}

但我认为主要问题是你在滥用ngDoCheck生命周期钩子。你为什么不对 Observables 做出反应呢?

combineLatest([
   this.storeWallets.loadInvoiceExtractionProduct(this.selectedWallet)
      .pipe(/* Add your catchError logic for only this observable */),
   this.storeWallets.loadInvoiceExtractionSupport(this.selectedWallet),
   this.storeWallets.loadInvoiceExtractionTraining(this.selectedWallet),
]).pipe(
   filter(results => results.every(res => !!res))
).subscribe(results => {
   // Called when all 3 returned positively
})
于 2019-05-09T10:18:55.200 回答