So here's the deal. I have a component thats very well written and being used in a lot of places. Now I need to use the same component, but want a different template to be rendered, based upon a condition.
I tried a lot.
1) Tried using multiple component decorators - no luck
2) Tried multiple level of abstractions, where I just ended up creating more components - bad idea
3) Can literally copy the whole component, and just change the selector and template - bad idea
4) Currently I was trying this:
<div *ngIf="!isWizard">
<ul class="nav" role="tablist">
<ng-content select="tab-link"></ng-content>
</ul>
<ng-content select="tab-content"></ng-content>
</div>
<div *ngIf="isWizard">
<nav class="nav-panel sidenav">
<ng-content select=".wizard-title"></ng-content>
<ul class="nav" role="tablist">
<ng-content select="tab-link"></ng-content>
</ul>
</nav>
<main class="settings-panel content-area">
<ng-content select="tab-content"></ng-content>
</main>
</div>
I set the isWizard property as true/false. Now the problem is, ng-content runs only once. So when isWizard is true, even though the div block is displayed, ng-content doesn't run ( cause it ran in the above block ).
5) Instead of using ngIf I also tried ngSwitch - didn't work
I'm desperate now. Please help :)
As far as I know it cannot be done using ng-content
but you could achieve this using templates
(or ng-templates
in Angular 4+). So instead of passing content directly to your component, just wrap it in <template>
like that:
<my-component [isWizard]="true">
<template>Hello World!</template>
</my-component>
Then you need to inject the template to your component with @ContentChild(TemplateRef)
and render it as many times as you wish.
@Component({
selector: "my-component",
template: `
<div *ngIf="!isWizard">
first: <template [ngTemplateRenderer]="template"></template>
</div>
<div *ngIf="isWizard">
second: <template [ngTemplateRenderer]="template"></template>
</div>`
})
export class MyComponent {
@ContentChild(TemplateRef)
private template: TemplateRef<any>;
@Input("isWizard")
private isWizard: boolean;
}
There is one last thing, our component uses ngTemplateRenderer
which is a simple utility directive that renders templates passed by reference. Here's the code for that directive:
@Directive({ selector: '[ngTemplateRenderer]'})
export class TemplateRenderer implements OnInit, OnDestroy {
@Input("ngTemplateRenderer")
private template: TemplateRef<any>;
private view: EmbeddedViewRef<any>;
constructor(private container: ViewContainerRef) {}
ngOnInit(): void {
this.view = this.container.createEmbeddedView(this.template);
}
ngOnDestroy(): void {
this.view.destroy();
}
}