乐趣区

关于angular:ngselect2发生ExpressionChangedAfterItHasBeenCheckedError异常的一种解决方法

驰名的 select2 终于有热心的大牛构建了 angular 版本,并命名为 ng-select2。但(猜测) 因为其外围的代码依赖于 jquery, 所以在联合formControl 应用时,会产生如下异样:Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'ng-pristine': 'true'. Current value: 'false'.

情景再现

比方咱们有以下组件树:

一个一般的 A 组件,一个能够实现了 ControlValueAccessor 接口并申明为 FormControl 的 B 组件,一个援用的 ng-select2 组件。

其中 A 组件蕴含 B 组件、B 组件又蕴含 ng-select2 组件。

ng-select2组件中的数据列表是通过资源申请失去的列表,所以是异步数据,B 组件 V 层示例如下:

<ng-select2
  [value]="datum"
  [data]="data"
  (valueChanged)="onChanged($event)"
</ng-select2>

B 获取 select2 应用的数据列表 data 示例代码如下:

ngOnInit(): void {this.service.getAll()
        .subscribe(data => {
            // 在这设置 ng-select2 的数据列表
            this.data = data;
        });
}

此时在 A 组件将会产生如下谬误:Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'ng-pristine': 'true'. Current value: 'false'.

起因猜测

咱们晓得,因为在大牛们会具体的解释异样产生的起因,所以解决问题的第一步也是最重要的一步便是翻译:
严重错误:表达式被检测结束当前却产生了变更谬误:当表达式被检测结束当前却又产生了变更。检测结束时,检测的 'ng-pristine' 的值为 'true'. 以后值为:'false'
同时 pristine 可译为 原始的

所以我猜错主大略是如下产生的:

也就是说:将 A 组件在渲染结束的状况下,发现 FormControl 的值产生了变动,则会产生 ExpressionChangedAfterItHasBeenCheckedError 异样。

解决办法

ng-select2 的官网 demo 中给出了当列表值异步时的解决方案,但遗憾的是该办法同样会引发上述异样。

该异样产生的次要起因是因为 A 组件处于渲染结束,使得 A 中做为 FormControl 的组件 B 同样处于 tHasBeenChecked 状态,所以解决该问题也能够如下着手:

如上图所示,当组件 B 在接管到异步数据时,为了避免其子组件 ng-select2 进行数据弹射时 A 组件处于 渲染结束 状态,咱们在此手动的触发从新渲染所有组件的办法。此时将 A 组件接管到最新的值时,其状态处于 渲染中 ,当然也就不会呈现HasBeenChecked 异样 了。

代码如下:

constructor(private service: Service,
  private changeDetectorRef: ChangeDetectorRef) {
}

ngOnInit(): void {this.service.getAll()
        .subscribe(data => {
            // 在这设置 ng-select2 的数据列表
            this.data = data;
            // 手动调用组件渲染办法,从新渲染各组件
            this.changeDetectorRef.detectChanges();});

总结

排错的路千万条,翻译、瞎猜第一条。

退出移动版