记录一下学习使用 ChildContent 的试验代码,用的是 Angular 19。
AppComponent 是 parent component, SidebarComponent 是 child component,SidebarBlogCategoriesComponent 是 projected component 。
代码1:使用 ng-content 在 child component 中显示 projected component 的内容
// SidebarBlogCategoriesComponent
@Component({
selector: 'cnb-sidebar-blog-categories',
template: `
<h1>Hello, World!</h1>
`
})
export class SidebarBlogCategoriesComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
// SidebarComponent
@Component({
selector: 'cnb-sidebar',
template: `
<p>SidebarComponent</p>
<ng-content></ng-content>
`
})
export class SidebarComponent implements OnInit {
@ContentChild(SidebarBlogCategoriesComponent) content?: SidebarBlogCategoriesComponent;
constructor() { }
ngOnInit() { }
ngAfterContentInit(): void {
console.log('content: ' + this.content);
}
}
// AppComponent
@Component({
selector: 'app-root',
imports: [SidebarComponent, SidebarBlogCategoriesComponent],
template: `
<p>AppComponent</p>
<cnb-sidebar>
<cnb-sidebar-blog-categories></cnb-sidebar-blog-categories>
</cnb-sidebar>
`
})
export class AppComponent {
}
运行时页面显示结果:
AppComponent
SidebarComponent
Hello, World!
代码2:Directive + TemplateRef 无法显示 projected component 的内容
这是园子博客后台从 angular 15 升级到 angular 19 后遇到的问题,详见 https://q.cnblogs.com/q/151579
注:下面的代码中用 [ngTemplateOutlet]
取代了 <ng-content>
import { NgIf, NgTemplateOutlet } from '@angular/common';
import { Component, ContentChild, Directive, OnInit, TemplateRef } from '@angular/core';
// SidebarContentDirective
@Directive({
selector: '[cnbSidebarContent]',
})
export class SidebarContentDirective {
constructor(public templateRef: TemplateRef<any>) { }
}
// SidebarBlogCategoriesComponent
@Component({
selector: 'cnb-sidebar-blog-categories',
template: `
<h1>Hello, World!</h1>
`
})
export class SidebarBlogCategoriesComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
// SidebarComponent
@Component({
selector: 'cnb-sidebar',
imports: [NgIf, NgTemplateOutlet],
template: `
<p>SidebarComponent</p>
<div class="sidebar-content" *ngIf="content && content.templateRef">
<ng-container [ngTemplateOutlet]="content.templateRef"></ng-container>
</div>
`
})
export class SidebarComponent implements OnInit {
@ContentChild(SidebarContentDirective) content?: SidebarContentDirective;
constructor() { }
ngOnInit() { }
ngAfterContentInit(): void {
console.log('content: ' + JSON.stringify(this.content));
}
}
@Component({
selector: 'app-root',
imports: [SidebarComponent, SidebarBlogCategoriesComponent],
template: `
<p>AppComponent</p>
<cnb-sidebar>
<cnb-sidebar-blog-categories *cnbSidebarContent></cnb-sidebar-blog-categories>
</cnb-sidebar>
`
})
export class AppComponent {
}
页面输出:
AppComponent
SidebarComponent
console.log 的输出:
content: undefined
代码3:通过 ng-template 引用变量解决 Directive + TemplateRef 的问题
解决方法来自 stackoverflow 上 Angular content projection in standalone component 问题的回答:
We cannot use a directive on ng-template since it does not fire, ng-template is a virtual element and is not rendered in the DOM, so the better option, is to just create template reference variables like #cardHeader and #cardMainContent and access these through ContentChild and directly render them on the HTML.
@ContentChild('cardMainContent') cardMainContent!: TemplateRef<any>; @ContentChild('cardHeader') cardHeader!: TemplateRef<any>;
解决问题的示例代码:
import { NgIf, NgTemplateOutlet } from '@angular/common';
import { Component, ContentChild, Directive, OnInit, TemplateRef } from '@angular/core';
// SidebarBlogCategoriesComponent
@Component({
selector: 'cnb-sidebar-blog-categories',
template: `
<h1>Hello, World!</h1>
`
})
export class SidebarBlogCategoriesComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
// SidebarComponent
@Component({
selector: 'cnb-sidebar',
imports: [NgIf, NgTemplateOutlet],
template: `
<p>SidebarComponent</p>
<div class="sidebar-content" *ngIf="content && content">
<ng-container [ngTemplateOutlet]="content"></ng-container>
</div>
`
})
export class SidebarComponent implements OnInit {
@ContentChild('sidebarContent') content?: TemplateRef<any>;
constructor() { }
ngOnInit() { }
ngAfterContentInit(): void {
console.log('content: ' + JSON.stringify(this.content?.elementRef));
}
}
@Component({
selector: 'app-root',
imports: [SidebarComponent, SidebarBlogCategoriesComponent],
template: `
<p>AppComponent</p>
<cnb-sidebar>
<ng-template #sidebarContent>
<cnb-sidebar-blog-categories></cnb-sidebar-blog-categories>
</ng-template>
</cnb-sidebar>
`
})
export class AppComponent {
}
页面显示结果:
AppComponent
SidebarComponent
Hello, World!
console.log 的输出:
content: {"nativeElement":{"__ngContext__":1}}
标签:SidebarComponent,记录,Component,AppComponent,SidebarBlogCategoriesComponent,conten
From: https://www.cnblogs.com/dudu/p/18658870