I have a problem with the new ng-content
transclusion.
Let's say I have a component my-component
that, in its ngOnInit()
function does some heavy operation on load (for now, just a console.log()
).
I have a wrapper, that displays the content via transclusion (my-wrapper.component.html
).
<ng-content></ng-content>
If I set the surroundings up like this, the log statement doesn't show:
<my-wrapper *ngIf="false">
<my-component></my-component>
</my-wrapper>
I assume, the my-wrapper
component does not get built, so the content is ignored.
But if I try to move the logic into the my-wrapper
component like this (my-wrapper.component.html
):
<ng-container *ngIf="false">
<ng-content></ng-content>
</ng-container>
I always see the console.log()
output. I guess, the my-component
gets built and then stored away until the *ngIf
becomes true
inside my-wrapper
.
The intention was to build a generic "list-item + detail" component. Say I have a list of N overview-elements (my-wrapper
), that get rendered in a *ngFor
loop. Every of those elements has its own detail component (my-component
) that is supposed to load its own data, once I decide to show more infos to a specific item.
overview.html:
<ng-container *ngFor="let item of items">
<my-wrapper>
<my-component id="item.id"></my-component>
</my-wrapper>
</ng-container>
my-wrapper.component.html:
<div (click)="toggleDetail()">Click for more</div>
<div *ngIf="showDetail">
<ng-content></ng-content>
</div>
Is there a way to tell Angular, to ignore the transcluded content until it is necessary to be added to the page? Analogously to how it was in AngularJS.
Based on the comment of @nsinreal I found an answer. I find it to be a bit abstruse, so I'm trying to post it here:
The answer is to work with ng-template
and *ngTemplateOutlet
.
In the my-wrapper
component, set up the template like this (my-wrapper.component.html
):
<div (click)="toggleDetail()">Click for more</div>
<div *ngIf="showDetail" [hidden]="!isInitialized">
<ng-container *ngTemplateOutlet="detailRef"></ng-container>
</div>
Note, that the [hidden]
there is not really necessary, it hides the "raw" template of the child until it decides it is done loading. Just make sure, not to put it in a *ngIf
, otherwise the *ngTemplateOutlet
will never get triggered, leading to nothing happening at all.
To set the detailRef
, put this in the component code (my-wrapper.component.ts
):
import { ContentChild, TemplateRef } from '@angular/core';
@Component({ ... })
export class MyWrapperComponent {
@ContentChild(TemplateRef) detailRef;
...
}
Now, you can use the wrapper like this:
<my-wrapper>
<ng-template>
<my-component></my-component>
</ng-template>
</my-wrapper>
I am not sure, why it needs such complicated "workarounds", when it used to be so easy to do this in AngularJS.