首页 > 其他分享 >Angular 中使用 ChildContent 记录

Angular 中使用 ChildContent 记录

时间:2025-01-08 11:32:42浏览次数:1  
标签:SidebarComponent 记录 Component AppComponent SidebarBlogCategoriesComponent conten

记录一下学习使用 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

相关文章

  • 记录一下uniapp vue3 mqtt app端的接入
    原生微信小程序MQTT.js可用版本有v4.2.1、v4.2.0、v4.1.0和v2.18.9npminstallmqtt@4.2.1||yarnaddmqtt@4.2.1使用uniapp框架搭建微信小程序MQTT.js可用版本有v4.1.0和v2.18.9npminstallmqtt@4.1.0||yarnaddmqtt@4.1.0app这里用npminstallm......
  • IBM Enterprise Records企业记录管理与档案管理系统的对比
    IBMEnterpriseRecords(IER)是一款专门设计用于企业内容管理和记录管理的解决方案,隶属于IBM的FileNet产品家族。它帮助组织管理电子和物理记录,确保合规性,支持信息生命周期管理,从而满足法规、政策和业务需求。以下是IER的详细介绍,包括功能、应用场景以及与中外同类产品的对比:......
  • 省选训练赛 #18 题目 D 补题记录
    题意:有\(n\)棵待种的植物,关系呈一张DAG,其中边\((u,v)\)表示必须等植物\(u\)成熟之后才能种下植物\(v\),第\(i\)棵植物种下后需要花费\(t_i\)时间成熟。你有\(m\)点魔法,可以使用\(d_i\)点魔法令\(t_i\)减一,可以多次对一棵植物使用魔法,求最终种完所有植物的最早时......
  • Vue学习记录14
    组件事件触发与监听事件在组件的模板表达式中,可以直接使用$emit方法触发自定义事件(例如:在v-on的处理函数中):<!--MyComponent--><button@click="$emit('someEvent')">ClickMe</button>父组件可以通过v-on(缩写为@)来监听事件:<MyComponent@some-event="callback"/&......
  • vllm 安装踩坑记录
    不太确定最直接简单的安装方法是什么,可以采用如下步骤安装:环境:cuda12.2,其他库的版本可以按如下requirements文件中指定的版本更新1.从git链接下载最新的vllm本地包到自定义目录./vllm_source_code/,依次安装该目录下requirements-build.txt等多个requirements文件中的依赖库,注意......
  • [题目记录]CF335F Buy One , Get One Free
    CF335FBuyOne,GetOneFree题意\(n\)个物品,价格为\(a_i\),每买一个物品\(i\)可以免费得到一个\(a_j<a_i\)的物品\(j\),问获取所有物品的最小花费.\(n\le5\times10^5\),\(1\lea_i\le10^9\).题解有一个最直接显然的贪心是买最大,送次大,以此类......
  • 【代码随想录】刷题记录(91)-根据身高重建队列
    题目描述:假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i]=[hi,ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。请你重新构造并返回输入数组 people 所表示的队列。返回的......
  • 【代码随想录】刷题记录(92)-用最少数量的箭引爆气球
    题目描述:有一些球形气球贴在一堵用XY平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i]=[xstart,xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切y坐标。一支弓箭可以沿着x轴从不同点 完全垂直 地射出。在坐标 x ......
  • [题目记录]loj#560 Menci的序列
    loj#560Menci的序列题意给出一个长为\(n\),由+和*组成的序列和常数\(k\).对于一个这样的序列,定义其权值为:初始权值为0,从左到右遍历序列如果当前位是+就把权值\(+1\)如果当前位是*就把权值\(\times2\)对\(2^k\)取模.求原序列的一个子序列,......
  • 【记录一个问题】macos arm64 中,使用 golang 的 atomic.LoadUint32() 得到的值是 0
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯在macosarm64下调试一个无锁算法的时候,总在莫名其妙的地方崩溃,后来发现是atomic.LoadUint32()的地方读到的值是0.1使用curItemLen:=atomic.LoadUint32(ne......