2

We have a standard modal within our application.

<ng-template [ngIf]="true" #editDataModal>
   <div class="modal-header">
     <h5 class="modal-title">Edit Modal</h5>
     <button type="button" class="close" aria-label="Close" (click)="onCancelClicked()">
       <span aria-hidden="true">&times;</span>
     </button>
   </div>
  <div class="modal-body" #editDataModalBody>CUSTOM COMPONENT GOES HERE</div>
 </ng-template>

We want to be able to pass in a custom component as our body. Is there a way in ngx bootstrap to do this?

It appears that the modal appears outside the main content so we can't find it using ViewChild.

We are calling it using the modal service. Like so:-

  constructor(
    private modalService: BsModalService
  ) { }

ngOnInit() {
   this.modalConfig = {
      ignoreBackdropClick: true
    };

   this.ModalRef = this.modalService.show(this.editModal, this.modalConfig);
}
Campey
  • 1,108
  • 9
  • 15

1 Answers1

0

The modal component could obtain and publish the ViewContainerRef. For example, it could use a BehaviorSubject. The parent component can create the custom component and add it to the modal when the viewContainerRef is published. I only did it this way instead of just a getter because ViewChild is not valid until afterViewInit so you need a way to handle that.

// EditModalComponent
export class EditModalComponent implements AfterViewInit {
  @ViewChild("editDataModalBody", {read: ViewContainerRef}) vc: ViewContainerRef;

  public bodyRefSubject: BehaviorSubject<ViewContainerRef> = new BehaviorSubject<ViewContainerRef>(null);

  constructor(
    public bsModalRef: BsModalRef,
    public vcRef: ViewContainerRef
  ) {}

  ngAfterViewInit() {
    this.bodyRefSubject.next(this.vc);
  }

  onCancelClicked() {
    console.log('cancel clicked');
    this.bsModalRef.hide()
  }
}

And in the parent component:

// Parent Component
export class AppComponent {
  bsModalRef: BsModalRef;
  bodyContainerRef: ViewContainerRef;
  customComponentFactory: ComponentFactory<CustomComponent>;
  modalConfig: ModalOptions;

  constructor(
    private modalService: BsModalService,
    private resolver: ComponentFactoryResolver
  ) {
    this.customComponentFactory = resolver.resolveComponentFactory(CustomComponent);
  }

  openModalWithComponent() {
    this.modalConfig = {
      ignoreBackdropClick: true,
    }
    this.bsModalRef = this.modalService.show(EditModalComponent, this.modalConfig);
    this.bsModalRef.content.bodyRefSubject.subscribe((ref) => {
      this.bodyContainerRef = ref;
      if (this.bodyContainerRef) {
        this.bodyContainerRef.createComponent(this.customComponentFactory);
      }
    })
  }
}

Another way without using ViewChild is to place a directive on the div instead of #editDataModalBody and that directive can inject the ViewContainerRef and publish it using a service or similar.

Thor
  • 251
  • 2
  • 9