angularcodepenng-templateng-contentng-container

Hey, so is there a way to nest ngTemplateOutlets? I am trying to create a simple customizable modal


I am trying to create a simple customizable modal. Where I can pass via Input() decorator a TemplateRefs and then my component would render that.

I am passing 2 TemplateRefs. 1 - The black backdrop, 2 - The dialog box. (I need the backdrop differently in other places in my app).

I am getting both inputs, and they work.** But they are created adjacent to each other, not nested.**

adjacent elements, not nested.

1

And without further adew, here it is...

<ng-container [ngTemplateOutlet]="backdropTemplate">
  <ng-container [ngTemplateOutlet]="dialogTemplate"></ng-container>
</ng-container>

I created a codepen to better demonstrate: https://codesandbox.io/embed/elastic-morning-fnxgeb?fontsize=14&hidenavigation=1&theme=dark

I have come to ngTemplateOutlet so that I can make my modal component generic. However, if I can't nest the DialogBox template, inside the backdrop template then I would rather just pass both. But I would like to see what you think!

I have been going at this for a few hours now, tried to surround with this. ng-content instead..


Solution

  • The biggest problem with this is that you need to somehow tell angular where to put the inner template. One solution I can think of is to use the context of the background-template to pass the inner template and let it handle the second template outlet by itself. Let me show you what I mean.

    Inside of the modal.component.html we do something like this:

    <ng-container
      *ngTemplateOutlet="backdropTemplate; context: { dialogTemplate: dialogTemplate}"
    ></ng-container>
    

    This tells the *ngTemplateOutlet directive to give the backdropTemplate the additional context specified. The backdropTemplate can now use this context like this:

    <ng-template #modalBackdrop let-innerTemplate="dialogTemplate">
        <div [ngClass]="{ 'modal-backdrop': true, 'backdrop-active': showModal }" (click)="toggleModal()">
        <ng-container *ngTemplateOutlet="innerTemplate"></ng-container>
      </div>
    </ng-template>
    

    So we essentially tell angular to bind the context variable dialogTemplate to the local variable innerTemplate and can use this to render it in another *ngTemplateOutlet. This is a technique often used in structural directives. The closest example I could find for this in the documentation is here.