Currently there is a bug related to the way that properties in td-layout components are set using the media service. Take as example:
<td-layout-nav-list #manageList [opened]="media.registerQuery('gt-sm') | async" [mode]="(media.registerQuery('gt-sm') | async) ? 'side' : 'over'"
[sidenavWidth]="(media.registerQuery('gt-xs') | async) ? '250px' : '65%'" logo="assets:warehouse" navigationRoute="/">
It will throw the following error:
LayoutPageComponent.html:1 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '[object Object]'. Current value: 'side'.
at viewDebugError (core.es5.js:8507)
at expressionChangedAfterItHasBeenCheckedError (core.es5.js:8485)
at checkBindingNoChanges (core.es5.js:8649)
at checkNoChangesNodeInline (core.es5.js:12504)
at checkNoChangesNode (core.es5.js:12476)
at debugCheckNoChangesNode (core.es5.js:13251)
at debugCheckDirectivesFn (core.es5.js:13153)
at Object.eval [as updateDirectives] (LayoutPageComponent.html:1)
at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13135)
at checkNoChangesView (core.es5.js:12296)
at callViewAction (core.es5.js:12660)
Another example:
<td-layout-manage-list #manageList [opened]="false" [mode]="'over'" [sidenavWidth]="(media.registerQuery('gt-xs') | async) ? '280px' : '70%'">
WIll cause the following:
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '[object Object]'. Current value: '280px'.
at viewDebugError (core.es5.js:8507)
at expressionChangedAfterItHasBeenCheckedError (core.es5.js:8485)
at checkBindingNoChanges (core.es5.js:8649)
at checkNoChangesNodeInline (core.es5.js:12506)
at checkNoChangesNode (core.es5.js:12476)
at debugCheckNoChangesNode (core.es5.js:13251)
at debugCheckDirectivesFn (core.es5.js:13153)
at Object.View_LayoutPageComponent_0._co [as updateDirectives] (LayoutPageComponent.html:1)
at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13135)
at checkNoChangesView (core.es5.js:12296)
at callViewAction (core.es5.js:12660)
No error should be triggered.
material: beta.6
covalent/core: beta.5
angular: 4.2.0 (all)
angular-cli: 1.1.1
A possible fix was pointed already by @emoralesb05
Promise.resolve(undefined).then(() => {
this.media.broadcast();
this._changeDetectorRef.markForCheck();
});
The way this is implemented in the current version of the covalent documentation page is:
//constructor of a component
constructor(private _changeDetectorRef: ChangeDetectorRef,
public media: TdMediaService) {}
ngAfterViewInit(): void {
// broadcast to all listener observables when loading the page
this.media.broadcast();
this._changeDetectorRef.detectChanges();
}
Yeah, this is a limitation in 4.2.0.. where you need to explicitly call a change detection cycle if you change any inputs in ngAfterViewInit.. since by then the change detections have finished.
There is nothing we can do internally in the TdLayout since those inputs never get in, they are checked before that and throw the error.
The correct fix is doing:
//constructor of a component
constructor(private _changeDetectorRef: ChangeDetectorRef,
public media: TdMediaService) {}
ngAfterViewInit(): void {
// broadcast to all listener observables when loading the page
this.media.broadcast();
this._changeDetectorRef.detectChanges();
}
The new angular version became more strict with change detection in component life hook cycles
Gonna add the faq label for this.
Created a PR to update docs with this
I would suggest to leave the issue open for a while so that ppl can see it. Furthermore it might be a good idea to update the changelog with this info 馃槃
Yup, will keep it open for now and create a patch release monday-tuesday to reference this and another bug found in loading haha
Thanks as always man!
@emoralesb05 : Will you be fixing the bug in loading? Or would your suggestion of using a delay through Promise.resolve() be the way to go?
I am facing some race conditions between the register and resolve calls sometimes.
@asaph26 well, i already fixed a bug i found in loading and its merged. https://github.com/Teradata/covalent/pull/682
Or are you referring to a diff one?
Since if you are calling the register in ngAfterViewInit for a loading directive, you would have to do the same thing and call this._changeDetectorRef.detectChanges()
The bug i fixed was for the full screen register in ngOnInit
Updated quickstart with this https://github.com/Teradata/covalent-quickstart/commit/51b725d17c3a3b272b5e28a6c6001130b37fe331
@emoralesb05 : It was the full screen loading. Thanks for the quick fix. Will try out with the latest nightly.
have u solved with TdLoadingService?
I insert this.loading.register(); on "onRequest" in request.interceptor.ts and cause:
TdLoadingComponent.html:1
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'true'. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?
Yup, fixed in #682
Already published the documentation updates and changelog here to view more info https://github.com/Teradata/covalent/blob/develop/docs/CHANGELOG.md#100-beta5-1-2017-06-12
So closing this now
I just got this again with 2.0.0-beta.2.
constructor(private loading: TdLoadingService, private route: ActivatedRoute, private changes: ChangeDetectorRef) {
}
ngOnInit() {
this.loading.register();
this.route.queryParams.subscribe(qs => {
if (qs['error']) {
this.loading.resolve(); // causes ExpressionChangedAfterItHasBeenCheckedError
// Expression has changed after it was checked. Previous value: 'mode: indeterminate'. Current value: 'mode: determinate'.
this.changes.detectChanges(); // attempts to fix, but doesn't
}
});
}