Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One Component Multiple Templates based on Condition

Tags:

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 :)

like image 581
Varun Joshi Avatar asked Jun 04 '16 20:06

Varun Joshi


People also ask

Can a component have multiple templates?

A component is composed of two Files Ts and HTML mainly. Html is the view. but you can not have multiple templates, as binding will be issue and rendering can not be done. Instead, you can have multiple components inside one component, with each having different templates you need.

Can we render multiple templates based on condition?

Note Although it's possible for a component to render multiple templates, we recommend using an if:true|false directive to render nested templates conditionally instead.

What are the elements that we can use in Angluar templates?

This template uses typical HTML elements like <h2> and <p> , and also includes Angular template-syntax elements, *ngFor , {{hero.name}} , (click) , [hero] , and <app-hero-detail> . The template-syntax elements tell Angular how to render the HTML to the screen, using program logic and data.


2 Answers

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();      } } 
like image 65
Slawomir Dadas Avatar answered Nov 28 '22 00:11

Slawomir Dadas


In recent version above can be done using *ngIf="somevar", while you can pass "somevar" value using @input.

Example:

import { Component, OnInit, Input, Output, EventEmitter} from '@angular/core';  import {SearchPipe} from './../filters/search.pipe';    @Component({    selector: 'itra-filter',    templateUrl: 'filter.component.html',    styleUrls: ['filter.component.scss'],    inputs:['IsCheckboxEnabled','IsRadioboxEnabled'],    outputs: ['itemClicked']  })  export class ItraFilterComponent {  	// Default Value  	public IsCheckboxEnabled:boolean = false;  	public IsRadioboxEnabled:boolean = false;    	constructor() {		  	}    	ngOnInit() {  		  	}  }
<span class="checkbox-control" *ngIf="IsCheckboxEnabled">          <i class="icon icon_Check-box_filled"   *ngIf="y.checked"></i>  				<i class="icon icon_Check-box" *ngIf="!y.checked">        </i>  </span>          <span class="radiobox-control" *ngIf="IsRadioboxEnabled">  				<i class="icon icon_Radio-button-filled" *ngIf="y.checked"></i>  				<i class="icon icon_Radio-button" *ngIf="!y.checked"></i>  </span>
like image 23
Sahil Gupta Avatar answered Nov 27 '22 23:11

Sahil Gupta