I tried writing a wrapper component which can be passed some text and some parameters, which would then format my text using bootstrap, based on these parameters.
I've tried this:
header-line.component.ts
@Component({ selector:'header-line', templateUrl: 'header-line.component.html' }) export class HeaderLineComponent { @Input level: number; // other inputs used for formatting skipped here } header-line.component.html
<div class="row"> <div class="col-sm-12"> <!-- would really be [className]="..." based on skipped inputs --> <header-wrapper [level]="level"> <!-- display of icon, based on skipped inputs --> <ng-content></ng-content> </header-wrapper> </div> </div> header-wrapper.component.ts
@Component({ selector: 'header-wrapper', templateUrl: './header-wrapper.component.html' }) export class HeaderWrapperComponent { @Input() level: number; } header-wrapper.component.html
<h1 *ngIf="level === 1"><ng-content></ng-content></h1> <h2 *ngIf="level === 2"><ng-content></ng-content></h2> <h3 *ngIf="level === 3"><ng-content></ng-content></h3> <h4 *ngIf="level === 4"><ng-content></ng-content></h4> <h5 *ngIf="level === 5"><ng-content></ng-content></h5> <span *ngIf="!level || level < 1 || level > 5"><ng-content></ng-content></span> Intended usage
Usage would be something along the lines of:
<header-line [level]="1" [...]="...">Just a test h1</header-line> <header-line [level]="2" [...]="...">Just a test h2</header-line> <header-line [level]="3" [...]="...">Just a test h3</header-line> <header-line [...]="...">Just a test span</header-line> Expected output
I would then have expected the output to create something equivalent to:
<div class="row"> <div class="cols-sm-12"> <h1>Just a test h1</h1> </div> </div> <div class="row"> <div class="cols-sm-12"> <h2>Just a test h2</h2> </div> </div> <div class="row"> <div class="cols-sm-12"> <h3>Just a test h3</h3> </div> </div> <div class="row"> <div class="cols-sm-12"> <span>Just a test span</span> </div> </div> Effective output
However, what I do get is the following:
<div class="row"> <div class="cols-sm-12"> </div> </div> <div class="row"> <div class="cols-sm-12"> </div> </div> <div class="row"> <div class="cols-sm-12"> </div> </div> <div class="row"> <div class="cols-sm-12"> <span>Just a test span</span> </div> </div> Problem analysis
It took me only a little while to find out that the cause of my problem is the repeated use of in header-wrapper.component.ts because it is apparently static and cannot be used dynamically.
The following two links explain why my expectations were disappointed:
https://github.com/angular/angular/issues/9173
https://github.com/angular/angular/issues/8563
Finding a solution
The following link on Stackoverflow shows how this can be done if only two cases need to be supported:
How to conditionally wrap a div around ng-content
Using that approach I managed the following:
Updated: header-wrapper.component.html
<h1 *ngIf="level && level === 1; else notOne"> <ng-container *ngTemplateOutlet="content"></ng-container> </h1> <ng-template #notOne> <h2 *ngIf="level && level === 2; else notTwo"> <ng-container *ngTemplateOutlet="content"></ng-container> </h2> </ng-template> <ng-template #notTwo> <h3 *ngIf="level && level === 3; else notThree"> <ng-container *ngTemplateOutlet="content"></ng-container> </h3> </ng-template> <ng-template #notThree> <h4 *ngIf="level && level === 4; else notFour"> <ng-container *ngTemplateOutlet="content"></ng-container> </h4> </ng-template> <ng-template #notFour> <h5 *ngIf="level && level === 5; else content"> <ng-container *ngTemplateOutlet="content"></ng-container> </h5> </ng-template> <ng-template #content> <ng-content></ng-content> </ng-template> This produces the desired output.
My question
Is this really the only way to do this? Or is there an easier way that I am missing?