Search code examples
angularundefined-behaviorng-bootstrapviewchildng-template

Angular: Cannot read property 'sendClassForm' of undefined inside ng-template of NgbModal


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...

What this is about

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.

What I've already tried

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...

Code (Stackblitz App)

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

The message error I get

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"


Solution

  • 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.

    Stackblitz App

    Parent Component

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

    Parent HTML

    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>
    

    Child Component

    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.