问题形容
我的 Component 里有一个 selectedPane 字段(第 56 行),作为数据源显示在 div 标签里(代码第 47 行):
代码第 51 行,我应用 @ViewChild 这个 query,将第 45 行的 div 元素,查问进去并通过 52 行的 set 函数,赋给 this.selectedPane.
运行时收到这条谬误音讯:
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ”. Current value: ‘undefined’.
问题剖析
从调试器里能看出,旧的 value 是 “”, 新的 value 是 undefined,因而抛出异样:
if (ngDevMode && isInCheckNoChangesMode()) {
// View engine didn't report undefined values as changed on the first checkNoChanges pass
// (before the change detection was run).
const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
if (!devModeEqual(oldValueToCompare, value)) {const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName);
}
// There was a change, but the `devModeEqual` decided that the change is exempt from an error.
// For this reason we exit as if no change. The early exit is needed to prevent the changed
// value to be written into `LView` (If we would write the new value that we would not see it
// as change on next CD.)
return false;
}
这个谬误在 Angular 官网的这个视频里有具体的解释:
如果在 Angular 框架执行完变更检测之后,再批改属性值,比方在 ngAfterViewInit
或者本文例子的 set 函数里,就会抛出这个异样。
解决方案
一种 StackOverflow 上常常提到的解决方案就是,应用 异步更新
, 将值的批改推延到下一次变更检测周期中执行:
应用 setTimeout
配合提早为 0
的调用形式,使得这个更新对应的检测,产生在下一次浏览器的宏工作队列中。
采纳立刻执行的 Promise
能够达到同样的成果:
Promise.resolve().then(() => this.loading false);
![](https://img-blog.csdnimg.cn/img_convert/25322fe43c081d144f8af96da180ec72.png)
![](https://img-blog.csdnimg.cn/img_convert/7b4957cd8b42d1ec79e0bd7d16271953.png)
谬误隐没了:![](https://img-blog.csdnimg.cn/img_convert/bea6d17d6dbde5f7ae5e3c136baa2afe.png)
另一种解决方案是,在 set 函数里批改了属性值之后,立刻 ` 手动 ` 触发一次 change detection:![](https://img-blog.csdnimg.cn/img_convert/2238d967cfff2194184077f41e21d5e8.png)
能实现同样的成果:![](https://img-blog.csdnimg.cn/img_convert/31094ef2caa2e58c89a091e4c888e735.png)