1

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?

1
  • The updated approach is the correct way to embed transcluded content in multiple places. Theres no more to it. You might want to watch youtube.com/watch?v=PTwKhxLZ3jI Commented Jan 31, 2019 at 9:29

1 Answer 1

2

Based on the video linked by Jota.Toledo I have come up with a more compact version.

Updated header-wrapper.component.html

<h1 *ngIf="level && level === 1"><ng-container [ngTemplateOutlet]="content"></ng-container></h1> <h2 *ngIf="level && level === 2"><ng-container [ngTemplateOutlet]="content"></ng-container></h2> <h3 *ngIf="level && level === 3"><ng-container [ngTemplateOutlet]="content"></ng-container></h3> <h4 *ngIf="level && level === 4"><ng-container [ngTemplateOutlet]="content"></ng-container></h4> <h5 *ngIf="level && level === 5"><ng-container [ngTemplateOutlet]="content"></ng-container></h5> <span *ngIf="!level || level < 1 || level > 5"><ng-container [ngTemplateOutlet]="content"></ng-container></span> 

This works just the same as my updated solution from the question, but I find this version more compact and more easily readable.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.