External angular elements don't detect changes of deferred data after first instantiation
See original GitHub issueI’m submitting a…
[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:
Current behavior
When dynamically loading an angular elements custom element from an external source (i.e. not a custom element that is defined in the same angular app, but say from assets or some url), the first time it’s rendered, everything works as usual. The second etc. time it’s rendered, all data that is set in the component is rendered fine as well, but change detection does not work anymore, so if data is changed by an http request or a timeout, the changes are not displayed.
To work around this issue, ChangeDetectorRef has to be injected into the external custom element component and detectChanges has to be called once all data is available.
Expected behavior
The change detection should work on subsequent instances just as in the first one without manually calling ChangeDetectorRef.detectChanges().
Minimal reproduction of the problem with instructions
i don’t know how to create a multi-project demo on stackblitz, so here’s here are the steps to reproduce:
- create a new angular project with @angular/elements
ng new custom-element-one --prefix ce1
cd custom-element-one
ng add @angular/elements
npm install @webcomponents/custom-elements --save
- modify app.module.ts to register custom element
const element = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('custom-element-one', element);
- in the component, set some data deferred with http request or setTimeout and make sure it’s bound in the template:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'ce1-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'custom-element-one';
ngOnInit(): void {
setTimeout(() => this.title = 'custom-element-one updated', 1000);
}
}
- build/concat etc.
- create a new standard angular project and put the output of custom-element-one into assets
- load the custom element using script tag(s), createElement and appendChild similar to this:
appendCustomElementWithUrls(name: string, urls: string[], target: HTMLElement) {
if (!customElements.get(name)) {
for (const url of urls) {
const script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
}
}
const component = document.createElement(name);
target.appendChild(component);
}
What is the motivation / use case for changing the behavior?
External custom elements should behave the same if they are added to the DOM once or twice.
This works:
import { Component, OnInit, ChangeDetectorRef, Input } from '@angular/core';
@Component({
selector: 'ce1-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
@Input()
title = 'custom-element-one';
constructor(private cd: ChangeDetectorRef) {} // <-- inject ChangeDetectorRef
ngOnInit(): void {
setTimeout(() => {
this.title = 'custom-element-one updated';
this.cd.detectChanges(); // <-- call detectChanges to update UI
}, 1000);
}
}
Environment
Angular version: 6.2.3
Browser:
- [x] Chrome (desktop) version 69.0.3497.100
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [x] Firefox version 61.0.1
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [x] Edge version 40.15063.674.0
For Tooling issues:
- Node version: v10.4.1
- Platform: Windows 10
Others:
i’ll continue looking into this, but since i’m not familiar with the angular code base, any hint on where to start looking would be helpful.
Issue Analytics
- State:
- Created 5 years ago
- Comments:5 (1 by maintainers)
Top GitHub Comments
This is most likely the same as #24181.
A fix has been committed to zone.js, but not released yet: #1133.
You can verify this by building your element with this library, elements-zone-strategy, which also implements a version of the fix.
Same problem! @remackgeek I f*****g love you! I’ve spent days trying to get this sucker to work. Just dropped this in and it works like a charm. Thank you so much!