Issue
I am trying to "steal" from the DOM the SVG code generated by an own component. I do it like this:
<my-own-component id="my-component-id" #myComponentId
[data]="data"></my-own-component>
onButtonClick() {
this.data = someData;
const svgCode = document.getElementById('my-component-id').innerHTML;
}
Also tried (also not working):
@ViewChild('myComponentId') myComponentId;
...
onButtonClick() {
this.data = someData;
const svgCode = this.myComponentId.nativeElement.children[0].innerHTML;
}
The problem is that I get the content before Angular has applied the changes caused by this.data = someData
, so the elements of the SVG are not included.
I have "solved" it introducing a 50ms timeout. This works, but is not a proper solution, is a bad patch:
this.data = someData;
await new Promise(resolve => setTimeout(resolve.bind(null, null), 50));
const svgCode = document.getElementById('my-component-id').innerHTML;
I would like to be able to wait for Angular to finish rendering the component. Is there any way to do it?
Thanks in advance.
Solution
Elezan, the problem is that you need "give a breath to Angular". If you has, e.g.
<div>{{data}}</div>
click(){
this.data="......."
//here you don't can check the value of innerHtml
}
This "breath" is use a setTimeout
<div>{{data}}</div>
click(){
this.data="......."
setTimeout(()=>{
//now here you can check the value of innerHtml
})
}
Think that Angular, when you call to click function, execute all the instructions and "repaint" the app. So in the first case you’re trying to get the innerHTML before Angular "repaint". Using a setTimeout you’re saying to Angular: "Hey! you repaint and, after, don’t forget the instructions into setTimeout" -see that setTimeout has no milliseconds-
Another way is inject in constructor ChangeDetectorRef and use markForCheck()
before try to get the innerHTML
Update Another example using observables
$observable.subscribe(res=>{
this.data=res
setTimeout(()=>{
..get the innerHTML
})
})
Or promise
$promise.then(
res=>{
this.data=res
setTimeout(()=>{
..get the innerHTML
}),
err=>{...}
)
Or await
:
const svgCode = await new Promise<string>(resolve => {
setTimeout(() => {
resolve(document.getElementById('my-component-id').innerHTML));
});
});