1

Angular ng-bootstrap Modal open doesn't support TemplateRef as custom component passed from template.

Initially I was expecting to use Modal something like this:

this.modalService.open(ModalWindowComponent, {
    body: EmployeeFormComponent,
    title: 'Employee',
    data: {
        age: 28
    }
});

with ModalWindowComponent template like this:

<div class="modal-dialog">
    <div class="modal-header">
        <h4 class="modal-title">{{modal.title}}</h4>
        <button type="button" class="close" aria-label="Close" (click)="modal.close()">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    <div class="modal-body">
        <ng-template [ngTemplateOutlet]="modal.body">
            <!-- example: <app-employee-form></app-employee-form> -->
        </ng-template>
    </div>
</div>

But then I realized it's impossible, or requires super complex logic with dynamic components creation. So, I decided to use recommended template-driven approach, having modal template in component template. But since I need custom body, I created ModalWindowComponent with this template:

<ng-template>
    <div class="modal-header">
        <h4 class="modal-title">{{title}}</h4>
        <button type="button" class="close" aria-label="Close" (click)="ref.dismiss()">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    <div class="modal-body">
        <ng-content></ng-content>
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-secondary" (click)="ref.close()">Cancel</button>
    </div>
</ng-template>

I was expecting to use it this way:

template

<button type="button" class="btn btn-primary" (click)="open(modal)">Open</button>
<app-modal-window [ref]="modal" [title]="'Title'" #modal>
    Body
</app-modal-window>

component

open(modal: NgbModalRef): void {
    this.modalService.open(modal).result.then((result: any) => {
        this.closeResult = `Closed with: ${result}`;
    }, (reason: any) => {
        this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
    });
}

But I see this error: No component factory found for [object Object]. Did you add it to @NgModule.entryComponents? I tried to fix it by adding ModalWindowComponent to entryComponents of related module, but it didn't help.

However, this works:

<button type="button" class="btn btn-primary" (click)="open(modal)">Open</button>
<ng-template #modal let-c="close" let-d="dismiss">
    <div class="modal-header">
        <h4 class="modal-title">Title</h4>
        <button type="button" class="close" aria-label="Close" (click)="d()">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    <div class="modal-body">
        Body
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-secondary" (click)="c()">Cancel</button>
    </div>
</ng-template>

So, the question is what am I doing wrong? Maybe there's a better way to achieve the desired behavior? I understand that Modal doesn't support class-driven custom body component, but seems like I can't get template-driven to work as well.

Demo: https://angular-v6amvy.stackblitz.io

Package versions:

Angular: 6.0.0

ng-bootstrap: 2.1.2

Bootstrap: 4.1.1

P.S. I also took a look at https://valor-software.com/ngx-bootstrap/#/modals and https://material.angular.io/components/dialog/overview, but seems like they don't support needed behavior as well.

1 Answer 1

1

It turns out the devil is in the details again.

ModalWindowComponent should be like this:

component

export class ModalWindowComponent {  
    @Input() title: string;
    @Input() close;
    @Input() dismiss;
}

template

<div class="modal-header">
    <h4 class="modal-title">{{title}}</h4>
    <button type="button" class="close" aria-label="Close" (click)="dismiss()">
        <span aria-hidden="true">&times;</span>
    </button>
</div>
<div class="modal-body">
    <ng-content></ng-content>
</div>
<div class="modal-footer">
    <button type="button" class="btn btn-secondary" (click)="close()">Cancel</button>
</div>

Usage should be like this:

<button type="button" class="btn btn-primary" (click)="open(modal)">Open</button>
<ng-template #modal let-c="close" let-d="dismiss">
    <app-modal-window [title]="'Title'" [close]="c" [dismiss]="d">
        Body
    </app-modal-window>
</ng-template>

Demo: https://angular-v6amvy-pttrng.stackblitz.io

Sign up to request clarification or add additional context in comments.

2 Comments

Any suggestion how are you loading the EmployeeFormComponent or any other component dynamically in ng-content under the modal body?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.