ng-content vs ng-template

ng-content and ng-template

ng-content

ng-content

Content Projection

(or Slot in some other technologies)

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content />
        </div>
    `,
})
export class MyCard {}

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            Card content
        </my-card>
    `,
    imports: [MyCard]
})
export class App {}

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            <my-content />
        </my-card>
    `,
    imports: [MyCard, MyContent]
})
export class App {}

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            <my-content />
        </my-card>
    `,
    imports: [MyCard, MyContent]
})
export class App {}

Multi slots

ng-content

@Component({
    selector: 'my-card-header',
    standalone: true,
    template: '<ng-content />'
})
export class MyCardHeader {}

@Component({
    selector: 'my-card-footer',
    standalone: true,
    template: '<ng-content />'
})
export class MyCardFooter {}


@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content select="my-card-header" />
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {}

Multi slots

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            <my-card-header>Header</my-card-header>
            <my-content />
            <my-card-footer>Footer</my-card-footer>
        </my-card>
    `,
    imports: [MyCard, MyCardHeader, MyCardFooter, MyContent]
})
export class App {}

Multi slots

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            <my-card-header>Header</my-card-header>
            <my-content />
            <my-card-footer>Footer</my-card-footer>
        </my-card>
    `,
    imports: [MyCard, MyCardHeader, MyCardFooter, MyContent]
})
export class App {}

Multi slots

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content select="my-card-header" />
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {}

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            <my-card-header>Header</my-card-header>
            <my-content />
            <my-card-footer>Footer</my-card-footer>
        </my-card>
    `,
    imports: [MyCard, MyCardHeader, MyCardFooter, MyContent]
})
export class App {}

Multi slots

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content select="my-card-header" />
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {}

ng-content

@Component({
    selector: 'app-root',
    standalone: true,
    template: `
        <my-card>
            <my-card-footer>Footer</my-card-footer>
            <my-content />
            <my-card-header>Header</my-card-header>
        </my-card>
    `,
    imports: [MyCard, MyCardHeader, MyCardFooter, MyContent]
})
export class App {}

Multi slots

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content select="my-card-header" />
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {}

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content select="my-card-header" />
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {}

Content Projection

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content select="my-card-header" />
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
}

Content Projection

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <!-- <ng-content select="my-card-header" /> -->
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
}

Content Projection

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <!-- <ng-content select="my-card-header" /> -->
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
}

Content Projection

<my-card>
    <my-card-header>Header</my-card-header>
    <my-content />
    <my-card-footer>Footer</my-card-footer>
</my-card>

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <!-- <ng-content select="my-card-header" /> -->
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
}

Content Projection

<my-card>
    <my-card-header>Header</my-card-header>
    <my-content />
    <my-card-footer>Footer</my-card-footer>
</my-card>

not projected

query works

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <!-- <ng-content select="my-card-header" /> -->
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
}

Content Projection

<my-card>
    <my-card-header>
        Header
    </my-card-header>
    <my-content />
    <my-card-footer>
        Footer
    </my-card-footer>
</my-card>

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <!-- <ng-content select="my-card-header" /> -->
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
}

Content Projection

ng-content

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <!-- <ng-content select="my-card-header" /> -->
            <ng-content />
            <ng-content select="my-card-footer" />
        </div>
    `,
})
export class MyCard {
  @ContentChild(MyCardHeader) cardHeader?: MyCardHeader;
  @ContentChildren(ElementRef) elementList!: QueryList<ElementRef<any>>;
}

Content Projection

ng-template

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-content />
        </div>
    `,
})
export class MyCard {}

ng-template

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-container *ngTemplateOutlet="template" />
        </div>
    `,
    imports: [NgTemplateOutlet]
})
export class MyCard {
  @ContentChild(TemplateRef, { static: true }) template!: TemplateRef<unknown>;
}

ng-template

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-container *ngTemplateOutlet="template" />
        </div>
    `,
    imports: [NgTemplateOutlet]
})
export class MyCard {
  @ContentChild(TemplateRef, { static: true }) template!: TemplateRef<unknown>;
}

😰

ng-template

@Component({
    selector: 'app',
    standalone: true,
    template: `
        <my-card>
            <ng-template> My Content </ng-template>
        </my-card>
    `,
    imports: [MyCard]
})
export class App {}

ng-template

@Directive({ selector: 'ng-template[my-card-header]', standalone: true })
export class MyCardHeader {}

@Directive({ selector: 'ng-template[my-card-footer]', standalone: true })
export class MyCardFooter {}

@Directive({ selector: 'ng-template[my-card-content]', standalone: true })
export class MyCardContent {}

@Component({
    selector: 'my-card',
    standalone: true,
    template: `
        <div class="card">
            <ng-container *ngTemplateOutlet="headerTemplate" />
            <ng-container *ngTemplateOutlet="template" />
            <ng-container *ngTemplateOutlet="footerTemplate" />
        </div>
    `,
    imports: [NgTemplateOutlet]
})
export class MyCard {
  @ContentChild(MyCardContent, { static: true, read: TemplateRef }) 
  template!: TemplateRef<unknown>;
  
  @ContentChild(MyCardHeader, { static: true, read: TemplateRef }) 
  headerTemplate!: TemplateRef<unknown>;
  
  @ContentChild(MyCardFooter, { static: true, read: TemplateRef }) 
  footerTemplate!: TemplateRef<unknown>;
}

Multi Slots

ng-template

@Component({
    selector: 'app',
    standalone: true,
    template: `
        <my-card>
            <ng-template my-card-header>
                My header
            </ng-template>
            <ng-template my-card-content>
                <my-content />
            </ng-template>
            <ng-template my-card-footer>
                My footer
            </ng-template>
        </my-card>
    `,
    imports: [MyCard, MyCardHeader, MyCardFooter, MyCardContent, MyContent]
})
export class App {}

Multi Slots

ng-template

@Component({
    selector: 'app',
    standalone: true,
    template: `
        <my-card>
            <ng-template my-card-header>
                My header
            </ng-template>

            <my-content *my-card-content />

            <ng-template my-card-footer>
                My footer
            </ng-template>
        </my-card>
    `,
    imports: [MyCard, MyCardHeader, MyCardFooter, MyCardContent, MyContent]
})
export class App {}

Multi Slots

ng-template

Dynamic Context

ng-template

Dynamic Context

ng-template

Default Content

ng-template

Inherit Injector

ng-template

Inherit Injector

https://www.youtube.com/watch?v=XE9dI8gSi9U

ng-template

Conditional Content

ng-template

Conditional Content

ng-template

Conditional Content

ng-template

Thank you

ng-content ng-template

By Chau Tran

ng-content ng-template

  • 133