Wanna see something cool? Check out Angular Spotify 🎧

Multiple ng-content

Problem

I have a component with multiple ng-content. Basically if you passed a routerLink Input into the component, it will render <a> tag, otherwise it will render <button> tag. Obviously it is not how you design a link component but it is a good example. I actually did it around 2016 when I was learning Angular 😂

@Component({
  selector: 'app-link',
  template: `
    <a *ngIf="routerLink" [routerLink]="routerLink">
      {{ routerLink }} - <ng-content></ng-content>
    </a>
    <button *ngIf="!routerLink">
      <ng-content></ng-content>
    </button>
  `,
  styles: [],
})
export class LinkComponent {
  @Input() routerLink: string
}

And you would probably notice that the <a> tag was render but nothing come has been projected into <ng-content>.

<app-link routerLink="active">My link</app-link>
<br />
<app-link>My button</app-link>

The result come, but only the My button text get projected.

Multiple ng-content

There are several issues has been created on the angular repository regarding this issue, for example #9173 and #22972.

Solution

Why it is working this way, I don’t think I can explain in an easy way for you. Therefore feel free to check misko’s detailed comment

One notable workaround can be found on #22972 nelisbijl’ comment. Essentially, you don’t try to render multiple ng-content, but putting ng-content inside an ng-template and render that template inside your ngIf.

@Component({
  selector: 'app-link-fixed',
  template: `
    <a *ngIf="routerLink" [routerLink]="routerLink">
      {{ routerLink }} -
      <ng-container *ngTemplateOutlet="contentTmpl"></ng-container>
    </a>
    <button *ngIf="!routerLink">
      <ng-container *ngTemplateOutlet="contentTmpl"></ng-container>
    </button>
    <ng-template #contentTmpl>
      <ng-content></ng-content>
    </ng-template>
  `,
  styles: [
    `
      :host {
        display: block;
      }
    `,
  ],
})
export class LinkFixedComponent {
  @Input() routerLink: string
}

Multiple ng-content

Source code

Published 10 Apr 2022

Read more

 — My React Reading List
 — Slick - prevent layout shift for your slider
 — CSS div jumped when adding a border
 — Align React Material UI Dialog to the top instead of center
 — TypeScript - Property 'onerror' does not exist on type 'EventTarget'

Follow @trungvose on Twitter for more!