Angular ngTemplate, ngTemplateOutlet, ngContent: Select Contents of Template

538 views Asked by At

Angular ngTemplate, ngTemplateOutlet, ngContent: Select Contents of Template

I have 2 components: AppComponent (<app></app>) and ModalComponent (<modal></modal>). Nothing is special about these other than:

  • ModalComponent leverages NgContent
  • AppComponent has a Template within its markup
modal.component.html
<div class="modal">
    <header class="modal header">
        <ng-content select=".modal.header.title"></ng-content>
        <span class="header close">X</span>
    </header>
    <main class="modal body">
        <ng-content select=".modal.body.content"></ng-content>
    </main>
    <footer class="modal footer">
        <menu class="footer button group">
            <ng-content select=".modal.footer.button"></ng-content>
        </menu>
    </footer>
</div>
app.component.html
<div id="whatTheWhat">
    <ng-container *ngTemplateOutlet="tpl"></ng-container>
</div>

<modal>
    <ng-container *ngTemplateOutlet="tpl"></ng-container>
</modal>

<ng-template #tpl>
    <h1 class="modal header title">Modal Content Works!!!</h1>
    <div class="modal body content">
        ...
    </div>
    <button class="modal footer button">Confirm!</button>
</ng-template>

Expected Behavior

Each of the children within [#tpl] gets projected into each ng-content where [select] reflects the child's className.

Issue

None of the content gets project, with 1 exception:

  • If I add class="modal template" to the ng-container and add ng-content with [select]=".modal.template" then it works, but only wholesale. That is, the entirety of the template content gets projected into a single slot.

Moreover, if you look at div#whatTheWhat in a DOM Inspector, you'll see that each of the template's children becomes a Direct Descendant of #whatTheWhat. This must mean that content-projection is occuring before 'outletting' the template.

Additional

We are on Angular 10 but I believe I wrote this code virtually exact in an Angular 7 app (and it worked fine), but perhaps something has changed since Angular 8+.

Obviously, given the "exception" under "Issue" (above) I could fractionate my template into each of its children, classify multiple ng-containers to reflect each ng-conent's selection, and have the content projected. If you've read this far, you can assume that's not what I want.

Question

Is there any way to "selectively project specific template content into another component"? Can you think of a way to accomplish this even using native HTML elements such as <template> and <slot>?

0

There are 0 answers