Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destroying and reloading a child component

Tags:

angular

I need to be able to completely reload a child component. It seems the best way to to acheive this is by using a simple *ngIf with a boolean value; Set false to remove the component, and then set to true to re-initialize it, ie:

<app-child *ngIf="enabled"></app-child>

However, it seems that just doing this isn't enough to quickly remove/reinitialize the component:

reloadTree(){
  this.enabled = false;
  this.enabled = true; // doesn't work- child ngOnInit isn't called
}

Rather, I have to use a setTimeout before it will work:

reloadTree(){
  this.enabled = false;
  const self = this;
  setTimeout(function(){
    self.enabled = true;
  }, 1);
}

I presume this is to do with the way Angular renders templates? This isn't paricularly elegant- can anyone suggest a better way to acheive what I'm trying to do here? Thanks

like image 853
Inigo Avatar asked Nov 28 '22 22:11

Inigo


1 Answers

So just for the record and without trying to argue if it's a clean way to do it or not, here's how you can work around the problem with the flag toggling. The main idea is to destroy the child component and create it again afterwards, which you can do with a simple *ngIf flag on the child component.

If the flag is toggled to false, the child component is destroyed and completely removed from the DOM. Afterwards you can set it to true again to create a new instance (if I'm not mistaken here).

The problem in the given code and the need for the workaround with the setTimeout method is that angular needs to be aware of changes to react to them. In this case the toggle in two lines of code may be just too quick for angular to even get hold of a change (or maybe the compiler even removes the first line at all, so nothing is ever changed, not sure though), therefore the component is neither removed nor is a new instance created.

reloadTree(){
  this.enabled = false; // switching to false
  this.enabled = true; // and back to true 
  // this does not notify angular that something has actually changed
}

What we need to do is to manually tell angular that a value has changed. This can be done through angulars ChangeDetectionRef class, which can be injected into the component. In between toggling the enabled flag, we notify angular to look for changes, so it can react to that by removing the component completely. Then we can set it back to true to create a new instance.

constructor(private changeDetector: ChangeDetectorRef){}

reloadTree(){
    this.enabled = false;
    // now notify angular to check for updates
    this.changeDetector.detectChanges();
    // change detection should remove the component now
    // then we can enable it again to create a new instance
    this.enabled = true; 
}
like image 160
Benedikt Schmidt Avatar answered Dec 06 '22 11:12

Benedikt Schmidt