2

I am trying to make a reusable quickView modal in my app to load any component dynamically using the ng-bootstrap modal library

It's working fine as far I am loading the same example component as shown in docs, but not for the components I created to test.

How can I use the quickView modal for dynamic components creation to load in modal-body?

https://stackblitz.com/edit/angular-quickview

I am using simple if/else to open a component in the modal based on name string.

<button class="btn btn-lg btn-outline-secondary mr-2" (click)="open('default')">Launch default</button>
<button class="btn btn-lg btn-outline-danger mr-2" (click)="open('red')">Launch red</button>
<button class="btn btn-lg btn-outline-primary" (click)="open('blue')">Launch blue</button>
open(name: string) {
    if (name === "default") {
      const modalRef = this.modalService.open(NgbdModalContent);
      modalRef.componentInstance.name = "Default";
    } else if (name === "red") {
      const modalRef = this.modalService.open(RedComponent);
      modalRef.componentInstance.name = "Red";
    } else if (name === "blue") {
      const modalRef = this.modalService.open(BlueComponent);
      modalRef.componentInstance.name = "Blue";
    }
  }

I also tried with componentFactoryResolver to inject my component into modal-body but that also throw error Error: Cannot read property 'viewContainerRef' of undefined

 <div class="modal-body">
      <ng-template quickView></ng-template>
 </div>
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
        RedComponent
      );
      const viewContainerRef = this.quickView.viewContainerRef;
      viewContainerRef.clear();

      const componentRef = viewContainerRef.createComponent<any>(
        componentFactory
      );
      componentRef.instance.name = "Red";

2 Answers 2

6
+50

You can try adding modal service so it can resolveComponentFactory custom components and in that case the modal will be singleton.

modal.service.ts

import { Injectable, ComponentFactoryResolver } from "@angular/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Injectable()
export class ModalService {
  constructor(
    private ngbModal: NgbModal,
    private componentFactoryResolver: ComponentFactoryResolver
  ) {}

  showDefaultModalComponent(theComponent: any, name: any) {
    const componenetFactory = this.componentFactoryResolver.resolveComponentFactory(
      theComponent
    );
    const modalRef = this.ngbModal.open(theComponent);
    modalRef.componentInstance.name = name;
    return modalRef;
  }

  showFeaturedDialog(theComponent: any, name: any) {
    const componenetFactory = this.componentFactoryResolver.resolveComponentFactory(
      theComponent
    );

    const modalRef = this.ngbModal.open(theComponent);
    modalRef.componentInstance.name = name;
    return modalRef;
  }
}

And then inject that service into the main component.

export class NgbdModalComponent {
  constructor(private customModal: ModalService) {}

  open(name: string) {
    if (name === "default") {
      this.customModal.showDefaultModalComponent(NgbdModalContent, "Default");
    } else if (name === "red") {
      this.customModal.showFeaturedDialog(RedComponent, "Red");
    } else if (name === "blue") {
      this.customModal.showFeaturedDialog(BlueComponent, "Blue");
    }
  }
}

In case you want to use quickView directive please check that the reason why your example is not working is in RedComponent and BlueComponent. You have added twice @Component decorator as seen on the example bellow:

enter image description here

Please see the edited and working Stackblitz example:

https://stackblitz.com/edit/angular-quickview-ykwz4i?file=src/app/modal-component.ts

Note: Entry components in Angular 11 are deprecitated.

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

4 Comments

thanks for the detailed answer, this made my day! Can I also add header, close button somehow in the dynamic showFeaturedDialog method to display header by default instead adding that in each component HTML?
Sadly ngbmodal doesn't support ng-content / content projection. There are some other ways to do that but you may get into complicating the code.
make sure to include ->providers: [ModalService, NgbActiveModal, NgbModal]
Do you have idea how to implement this, if instead of Component the source of NgbModal is TemplateRef?
-1

You can inject the components dynamically in modal by declaring those components in entryComponents in your app module as follows.

    @NgModule({
    declarations: [
        AppComponent,
        RedComponent,
        BlueComponent
    ],
    imports: [
        BrowserModule,
        FormsModule,
        BrowserAnimationsModule,
    ],
    providers: [],
    entryComponents: [RedComponent, BlueComponent],
    bootstrap: [AppComponent]
  })
  export class AppModule { }

1 Comment

That doesn't work when I want to dynamically load different components into same modal stackblitz.com/edit/angular-quickview

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.