elnezah
elnezah

Reputation: 460

Get innerHTML from component AFTER render

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.

Upvotes: 0

Views: 2576

Answers (3)

Eliseo
Eliseo

Reputation: 58019

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));
    });  
}); 

Upvotes: 1

Ajit1803
Ajit1803

Reputation: 31

You just need to add AfterViewInit lifecycle hook with the class. I would also suggest that you assign the property within the OnInit lifescycle as well. Your parent component should look like this

export class appComponent implements OnInit, AfterViewInit{

 ngOnInit(): void {
  this.data = someData;
 }
 ngAfterViewInit(): void{
  const svgCode = document.getElementById('my-component-id').innerHTML;
 }

}

Upvotes: 0

ng-sierra
ng-sierra

Reputation: 1

Try AfterViewInit lifecycle hook. It's implementing like this

export class MyComponent implements AfterViewInit {
  ngAfterViewInit() {
    // code that should be executed after view initialization
  }
}

Upvotes: 0

Related Questions