Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to prevent child components from being created if ng-content is not present in template?

Tags:

angular

I am trying to create a tab component with a structure similar to this:

<tabs>
    <tab-item [title]="'Tab 1'">
        **child component that makes database calls in NgOnInit or NgAfterViewInit**
    </tab-item>
    <tab-item [title]="'Tab 2'">
        **child component that makes database calls in NgOnInit or NgAfterViewInit**
    </tab-item>
    <tab-item [title]="'Tab 3'">
        **child component that makes database calls in NgOnInit or NgAfterViewInit**
    </tab-item>
</tabs>

I have conditional logic to ensure that the child components are only rendered via ng-content if they are on the selected tab with the following snippet:

<ng-content *ngIf="selected"></ng-content>

While this works as anticipated from a UI perspective, it appears the child elements are still being created internally even though they are never rendered. This is something I would like to avoid since it is causing database calls that won't be needed until the user selects the appropriate tab.

I have created a greatly simplified example to illustrate this. As you can see I have commented out the ng-content from the template of ChildComponent, but the call to console.log from the ThirdComponent is still firing.

Is there any way to prevent this from happening? I could probably create an interface on components that will be displayed in tabs and then call a custom method to trigger database calls rather than using the built-in Angular lifecycle methods, but I'd like to avoid that if at all possible.

Thanks for any help you can provide!

like image 276
JKasper11 Avatar asked Oct 18 '22 19:10

JKasper11


1 Answers

I found this article to be extremely helpful in solving my problem.

I changed the template of my tab-item component to look like this:

<ng-content *ngIf="selected"></ng-content>
<template *ngIf="selected && templateRef" [ngTemplateOutlet]="templateRef"></template>

With templateRef being an input property:

@Input() templateRef: TemplateRef<any>;

To use this component, I can now do the following:

<tabs>
    <tab-item [title]="'Tab 1'">
        **static content**
    </tab-item>
    <tab-item [title]="'Tab 2'" [templateRef]="tab2"></tab-item>
    <tab-item [title]="'Tab 3'" [templateRef]="tab3"></tab-item>
    <template #tab2>
        **child component that makes database calls in NgOnInit or NgAfterViewInit**
    </template>
    <template #tab3>
        **child component that makes database calls in NgOnInit or NgAfterViewInit**
    </template>
</tabs>

Anything that's inside of a template will only be loaded when the tab is selected, preventing an extremely heavy initial page load.

like image 174
JKasper11 Avatar answered Nov 02 '22 03:11

JKasper11