Alright, first, I've already searched this problem like mad and found some solutions (some explained here), but none of them explain an efficient way to do it. So, here I go...
I'm creating a modal which uses ng-bootstrap. I made a component of a form to reutilize it in other pages. I put this component inside the modal. I need to reach this component's variables and methods from the Parent, so I set a ViewChild variable in the Parent's component and set it to the Child Component.
When I open the modal, the component shows with no problem. The problems comes when I click on the Create button. When the user clicks on the Create button the parent (which contains the modal) executes the Child's method to send the form but the Parent can't reach the Child's method because it is undefined, even though the modal is already opened.
I've tried putting the Child component outside the ng-template and it works just fine, but I need it in a modal.
I've also tried passing the Component with a #id on the directive to the method of the parent in order to execute the child's method. It works, but makes the code dirtier and brings more problems in the future. (This is actually myself of the future that got more problems with this implementation.)
If someone wonders what kind of problems it brings, I need to nest more components to the child's component so, because this 'grandchild' component it's still in the ng-template, the problem repeats and now I have to make the code dirtier again...
Here's a Stackblitz App I made. I kept it pretty simple and excluded unnecessary parts of the code which are not relevant to the problem. Stackblitz App
This is the error message I get:
ERROR TypeError: Cannot read property 'sendClassForm' of undefined
I've read that when ng-template has not been rendered yet (like the modal hasn't been opened) you get this undefined
error, but I don't get why it still happens when it's already opened.
Angular Version: 8.1.2
"@ng-bootstrap/ng-bootstrap": "^5.1.0"
Thanks to @yurzui that insisted on his solution, I came up with another solution which I consider almost the same as having the ViewChild but with no problems.
Here's the Stackblitz code in case you want to see it straight away, instead of my explanation.
I set a property, same as with the ViewChild but deleting the ViewChild part.
classFormComponent: ClassFormComponent; // No 'ViewChild(...)' part
And also created a method to save, to the variable above, the reference of the child component when needed.
// This method will be called by the ClassFormComponent when it gets ready to be used by the Parent.
saveReference( classFormComponent: ClassFormComponent ) {
this.classFormComponent = classFormComponent;
}
Then, I set a listener to the app-class-form
so when the child gets ready, it can tell the parent by calling the parent's method explained above.
<app-class-form (componentIsReady)="saveReference( $event )"></app-class-form>
The child has an Output EventEmitter.
@Output() componentIsReady: EventEmitter<ClassFormComponent> = new EventEmitter();`
And this event is emitted in the ngOnInit life cycle phase.
ngOnInit() {
// At this point, child component is born and it's ready to be used by the parent.
this.componentIsReady.emit(this);
}
This way, the parent gets access to the child's methods and attributes.
I say this is the inverse solution to the one I had because now the child reaches the parent when ready and, only then, the parent saves the reference to it.