Search code examples
angularviewchild

Error: ViewContainerRef.insert() is not a function when trying to add embeddedview into <ng-container>


I'm trying to implement a modal in my app by following the guide (the portion using ng-template) below

https://blog.bitsrc.io/creating-modals-in-angular-cb32b126a88e#:~:text=Different%20methods%20and%20tools%20for%20building%20modals%20in%20Angular&text=Modals%20are%20one%20of,already%20heavy%20with%20HTML%20elements.

Thing is, I'm getting an error in the console whenever I try to click on the button to open the modal: "this.vc.insert is not a function". I've read that we should use the ngAfterViewInit hook, but I'm not sure how to apply it as I only want the modal to show when the user clicks the button and not when ngAfterViewInit fires.

Below are some code snippets

.ts file

import { Component, OnInit, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core';
@Component({
    selector: 'app-browse-food',
    templateUrl: './browse-food.component.html',
    styleUrls: ['./browse-food.component.css']
})
export class BrowseFoodComponent implements OnInit {
    constructor() {
    }

    ngOnInit() {
        // unrelated code
    }

    @ViewChild('orderModal') orderModal: TemplateRef<any>;
    @ViewChild('vc') vc: ViewContainerRef;

    openModal() {
        let view = this.orderModal.createEmbeddedView(null);
        this.vc.insert(view);
    }
    closeModal() {
        this.vc.clear();
    }

html

<button (click)="openModal()">Open Modal</button>
<ng-container #vc></ng-container>

<ng-template #orderModal>
    <div class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <i (click)="closeModal()"></i>
            </div>
            <div class="modal-body">
                
            </div>
        </div>            
    </div>
</ng-template>

Any help is appreciated, TIA :)


Solution

  • Changing @ViewChild('vc') vc: ViewContainerRef; to @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef; gets it to work.

    Stackblitz eg.

    Using @ViewChild('vc') vc: ViewContainerRef; makes this.vc an ElementRef, not a ViewContainerRef as expected. Consequently the ElementRef this.vc has no method named insert.

    Using @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;, Angular explicitly gives you the ViewContainerRef associated with the #vc local reference. Here's a small and fuller explanation.