网站搜索

angular - 表达式更改问题


场景:

在左侧,显示所有未付款的账单。当用户点击某个账单时,其详细信息会显示在右侧。如果用户点击支付按钮,则账单被支付,这意味着它不应出现在左侧。这个过程会持续下去。

问题:

我设法支付了账单,已支付的账单从左侧消失。问题是点击左侧的下一个账单会出现此错误。

运行时错误 ExpressionChangedAfterItHasBeenCheckedError:表达式在被检查后已更改。之前的值:'true'。当前值:'false'。

屏幕录制:

代码 :

账单结算.ts

@IonicPage()
@Component({
  selector: 'page-bill-settlement',
  templateUrl: 'bill-settlement.html',
})
export class BillSettlement {
  billItem: BillDetail
  updateItem: boolean
  ...
  onBillSelected(billData: BillDetail) {
    this.billItem = billData
  }
  isUpdate(updateData: boolean) {
    this.updateItem = updateData
  }
}

账单结算.html

...
<page-bill-list (BillSelected)="onBillSelected($event)" [updateItem]="updateItem"></page-bill-list>
...
<page-bill-details (isUpdate)="isUpdate($event)" [billItem]="billItem"></page-bill-details>

账单列表.ts

@IonicPage()
@Component({
  selector: 'page-bill-list',
  templateUrl: 'bill-list.html',
})
export class BillList {
  billItems: BillDetail[] = []
  billItem = new BillDetail()
  @Input() updateItem: boolean
  @Output() BillSelected: EventEmitter<BillDetail> = new EventEmitter<BillDetail>()
  constructor(...) {
    this.billSrv.getBills()
      .subscribe(data => {
        this.billItems = data
      })
  }
  ngOnChanges(updateItem: boolean) {
    if (this.updateItem == true) {
      this.billSrv.getBills()
        .subscribe(data => {
          this.billItems = data
        })
    }
  }
  getBillDetails(item: BillDetail) {
    this.BillSelected.emit(item)
  }
}

账单列表.html

<ion-buttons>
  <button ion-button *ngFor="let item of billItems" (click)="getBillDetails(item)">Bill {{item.BillNo}}</button>
</ion-buttons>

账单详情.ts

@IonicPage()
@Component({
  selector: 'page-bill-details',
  templateUrl: 'bill-details.html',
})
export class BillDetails {
  ...
  @Input() billItem: BillDetail
  @Output() isUpdate: EventEmitter<boolean> = new EventEmitter<boolean>()
  ...
  ngOnChanges(billItem: BillDetail) {
    this.isUpdate.emit(false) //if this part is commented
//the bills are paid but the left side is not reloaded from the second time
  }
  settleBill() {
    ...
    this.billSrv.settleBill(...).subscribe(
      data => {
        if (data) {
          this.isUpdate.emit(true) //so the bill list is reloaded
        }
        else {
          ...
        }
      }
    )
  }
}

答案#1

运行时错误 ExpressionChangedAfterItHasBeenCheckedError:表达式在被检查后已更改。之前的值:'true'。当前值:'false'。

这个错误通常发生在开发环境(DEV),因为开发环境会运行额外的变化检测周期。当一个值在冗余的变化检测周期之间发生变化时,就会出现这个错误。这意味着某些东西以或多或少不受控制的方式更改了值。在变化检测运行之后,值预计会保持相对稳定,直到下一次显式的变化检测周期。开发环境中的冗余变化检测周期会捕捉到值意外变化的情况。

这通常指的是您的组件中值传播方式存在问题,但在某些情况下,您拥有的行为正是您想要的。在这种情况下,您可以通过添加来修复此错误

import { ChangeDetectorRef} from '@angular/core';

constructor(
    private cdr: ChangeDetectorRef
  ) { }

然后在你的值发生变化并且你明确想要再次调用变更检测的地方使用 this.cdr.detectChanges();。

再次,通常这个错误指出了你的某个值在生产环境中可能会引起问题,因为该值在变化检测周期之后发生了变化。开发模式只会在第一次变化检测后运行第二轮变化检测,以便捕捉你需要注意的这种情况。

希望这能帮到你。

从技术上讲,你可以在以下内容之后添加 detectChanges:

ngOnChanges(billItem: BillDetail) {
    this.isUpdate.emit(false) //if this part is commented
//the bills are paid but the left side is not reloaded from the second time
  }

问题就会消失,但你可能不想那样做。看,this.isUpdate.emit(false) 会在每次 ngOnChanges 触发时执行。它也会在每次 @Input() billItem: BillDetail 变化时执行。这可能不是你想要的。你可能希望将 this.isUpdate.emit(false) 移到其他地方,在你明确调用它的地方执行。

答案#2

上述错误通常在我们尝试修改在组件创建期间使用的值时出现。我自己也遇到过同样的问题。进行了以下更改并解决了错误。希望这也能对你有所帮助。

我的需求是向表格中插入行。每行有两列,一列是输入,另一列是单位。一旦添加完成,光标应该聚焦/激活在输入字段中。做了以下代码更改,哇啦……表达式错误消失了

代码:

ngAfterViewInit() {
       setTimeout (() => {
        if (!isNullOrUndefined(this.input.nativeElement)) {
          this.editingActive = true;
          this.input.nativeElement.focus();
          this.input.nativeElement.click();
              }
      }
    , 0);
  }