Please have a look at the Stackblitz Editor link. I've set up one angular application.
Brief working overview of the angular app
- Two ponents i.e app-ponent and child-ponent
- Initially, child ponent not display. There is a button in the parent app ponent when we click on the button, we enable one variable 'this.showChildComponent = true'.
- child ponent controlled by the variable this.showChildComponent.
- I'm using the 'firstParam' and 'secondParam' as a variable and sending these variables values to the child ponent.
Now, Please have a look at the issue
When we click on the button as I explained above, child ponent mounted and ngOnInit method will be called, you can also check the message on the console screen 'ngOnInit called: child ponent' but if I again click on the button, then the child ponent not re-render again and thus, ngOnInit method of child ponent not called.
// This method is defined in the app-ponent (parent) and it is called when user clicks on
// button
showChild() {
if (this.showChildComponent)
{
this.showChildComponent = false;
}
this.showChildComponent = true;
// child ponent ngOnInit call when
// I use the timer
// setTimeout(()=> {this.showChildComponent = true;}, 10);
this.firstParam = 'first param from parent';
this.secondParam = 'second param from parent';
}
// Parent ponent - app-ponent
<button (click)="showChild()">Click here to display the child ponent</button>
<div *ngIf="showChildComponent">
<app-child-ponent
[first_param]="firstParam"
[second_param]="secondParam"
></app-child-ponent>
</div>
As you can see in the code, if I use the setTimeout then child ponent ngOnInit method will be called whenever I click on the parent ponent button. But I don't want to use the timer here, what is the alternative solution to resolve this issue? whenever user clicks on the button, ngOnInit method of child ponent should be call.
Please have a look at the Stackblitz Editor link. I've set up one angular application.
Brief working overview of the angular app
- Two ponents i.e app-ponent and child-ponent
- Initially, child ponent not display. There is a button in the parent app ponent when we click on the button, we enable one variable 'this.showChildComponent = true'.
- child ponent controlled by the variable this.showChildComponent.
- I'm using the 'firstParam' and 'secondParam' as a variable and sending these variables values to the child ponent.
Now, Please have a look at the issue
When we click on the button as I explained above, child ponent mounted and ngOnInit method will be called, you can also check the message on the console screen 'ngOnInit called: child ponent' but if I again click on the button, then the child ponent not re-render again and thus, ngOnInit method of child ponent not called.
// This method is defined in the app-ponent (parent) and it is called when user clicks on
// button
showChild() {
if (this.showChildComponent)
{
this.showChildComponent = false;
}
this.showChildComponent = true;
// child ponent ngOnInit call when
// I use the timer
// setTimeout(()=> {this.showChildComponent = true;}, 10);
this.firstParam = 'first param from parent';
this.secondParam = 'second param from parent';
}
// Parent ponent - app-ponent
<button (click)="showChild()">Click here to display the child ponent</button>
<div *ngIf="showChildComponent">
<app-child-ponent
[first_param]="firstParam"
[second_param]="secondParam"
></app-child-ponent>
</div>
As you can see in the code, if I use the setTimeout then child ponent ngOnInit method will be called whenever I click on the parent ponent button. But I don't want to use the timer here, what is the alternative solution to resolve this issue? whenever user clicks on the button, ngOnInit method of child ponent should be call.
Share Improve this question asked Dec 31, 2019 at 12:06 ShubhamShubham 1,2012 gold badges17 silver badges39 bronze badges 5- what you want to achieve in child ponent when user clicks on button again ? – YogendraR Commented Dec 31, 2019 at 12:37
- @YogendraR whenever the user clicks on the button, ngOnInit method of child ponent should be called. – Shubham Commented Dec 31, 2019 at 12:42
- that's what I am asking, what you want to do inside ngOnInit with every button click. What is the use case here ? As I can see, you don't want to destroy child either. – YogendraR Commented Dec 31, 2019 at 12:47
- @Shubham you have set it to false and then true before the change detection has had a chance to read that there is a change. This means that the child ponent will not be removed and then re-added. This is why it works by using a timeout, because the timeout will get executed after the change detection. If you really want the behavior to run in the ngOnInit then you would need to use a settimeout to wait for the ponent to be destroyed. – jgerstle Commented Dec 31, 2019 at 13:05
- @jgerstle thanks for your input and time. But is there an alternate approach to destroy the child ponent? – Shubham Commented Dec 31, 2019 at 13:08
4 Answers
Reset to default 2Copied from ment to give a bit of reference for the answer:
You have set it to false and then true before the change detection has had a chance to read that there is a change. This means that the child ponent will not be removed and then re-added. This is why it works by using a timeout, because the timeout will get executed after the change detection. If you really want the behavior to run in the ngOnInit then you would need to use a settimeout to wait for the ponent to be destroyed.
Since it seems that you don't want to use the setTimeout, even though that's how I'd suggest doing it, you can force the change detection using one of the methods provided here. Here is a stackblitz fork from your original question, using the third approach.
Try this one to toggle your ponent:
showChild() {
this.showChildComponent = !this.showChildComponent;
this.firstParam = 'first param from parent';
this.secondParam = 'second param from parent';
}
You need to add some additional condition to your if
statement. Right now, the logic always assigns this.showChildComponent
to true
(even after you've assigned it to false
). Change your showChild
method to:
showChild() {
if (this.showChildComponent)
{
this.showChildComponent = false;
} else {
this.showChildComponent = true;
}
// child ponent ngOnInit call when
// I use the timer
// setTimeout(()=> {this.showChildComponent = true;}, 10);
this.firstParam = 'first param from parent';
this.secondParam = 'second param from parent';
}
You were previously always setting the showChildComponent
attribute to true
and never were destroying the child. Thus, it was never re-rendering.
For this you can manually trigger the child ponent by using ChangeDetectorRef
Create an instance of ChangeDetectorRef
and use like this below in app ponent.
this.changeDetectorRef.detectChanges();
Or Alternative way to achieve this is to use ngOnChanges, which will change everytime when you pass params as Input to child ponent. Here is a stackblitz fork by using ngOnChanges lifecycle hook.