首页 新闻 会员 周边 捐助

Angular 项目迁移到 Standalone Components 后遇到一个 Component 代码不执行的问题

0
悬赏园豆:30 [已解决问题] 解决于 2025-01-08 12:55

这是园子博客后台升级到 Angular 19 并迁移到 Standalone Components 后遇到的问题

posts-sidebar.component.ts 组件中的 <cnb-sidebar-blog-categories> 对应的 component 代码没有执行

@Component({
    selector: 'cnb-posts-sidebar',
    template: `
        <ng-template cnbLayoutSidebar>
            <cnb-sidebar header="博客后台"
                         [items]="operations"></cnb-sidebar>
            <cnb-sidebar header="分类">
                <cnb-sidebar-blog-categories *cnbSidebarContent></cnb-sidebar-blog-categories>
            </cnb-sidebar>
        </ng-template>
    `,
    imports: [SidebarComponent, SidebarBlogCategoriesComponent, LayoutSidebarDirective]
})

就是这部分,

<cnb-sidebar-blog-categories *cnbSidebarContent></cnb-sidebar-blog-categories>

cnbSidebarContent 是一个 @Directive,对应的实现代码如下:

@Directive({
    selector: '[cnbSidebarContent]',
})
export class SidebarContentDirective {
    constructor(public templateRef: TemplateRef<any>) { }
}
问题补充:

如果去掉 *cnbSidebarContent directive,<cnb-sidebar-blog-categories> 的组件代码就会执行

问题与 <cnb-sidebar header="分类"> 对应的 SidebarComponent 有关

SidebarComponent.ts

@Component({
    selector: 'cnb-sidebar',
    templateUrl: './sidebar.component.html'
})
export class SidebarComponent implements OnInit, OnDestroy {
    @Input() header = '';
    @Input() items: ISidebarItem[] = [];
    @ContentChild(SidebarContentDirective) content?: SidebarContentDirective;
}

注:cnbSidebarContent 起作用是因为上面的 @ContentChild(SidebarContentDirective) 部分的代码

sidebar.component.html

<div class="header">
    <!-- ... -->
    <div class="sidebar-content"
         *ngIf="content && content.templateRef && (!items || items.length <= 0)">
        <ng-container [ngTemplateOutlet]="content.templateRef"></ng-container>
    </div>
</div>

出问题时,上面的 content 的值是 undefined

dudu的主页 dudu | 高人七级 | 园豆:28576
提问于:2025-01-07 12:14

开头的 * 表示给 <cnb-sidebar-blog-categories> 外包一个 <ng-template>

dudu 2周前

<cnb-posts-sidebar> 是 parent component,<cnb-sidebar> 是 child component,<cnb-sidebar-blog-categories> 是 projected component

dudu 2周前
< >
分享
最佳答案
0

终于解决了!问题的原因是 Standalone Component 不支持在 ViewChild 中使用 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>;

具体解决方法如下:

  • 在 posts-sidebar.component.ts 组件中

<cnb-sidebar header="分类">
    <cnb-sidebar-blog-categories *cnbSidebarContent></cnb-sidebar-blog-categories>
</cnb-sidebar>

改为

<cnb-sidebar header="分类">
    <ng-template #sidebarContent>
        <cnb-sidebar-blog-categories></cnb-sidebar-blog-categories>
    </ng-template>
</cnb-sidebar>
  • 在 SidebarComponent.ts 中

@ContentChild(SidebarContentDirective) content?: SidebarContentDirective;

改为

@ContentChild('sidebarContent') content?: TemplateRef<any>;
  • 在 SidebarComponent.html 中

<div class="sidebar-content" *ngIf="content && content.templateRef && (!items || items.length <= 0)">
    <ng-container [ngTemplateOutlet]="content.templateRef"></ng-container>
</div>

改为

<div class="sidebar-content" *ngIf="content && (!items || items.length <= 0)">
    <ng-container [ngTemplateOutlet]="content"></ng-container>
</div>

示例代码详见博文 https://www.cnblogs.com/dudu/p/18658870

dudu | 高人七级 |园豆:28576 | 2025-01-08 12:22
其他回答(1)
0

帮顶...................

收获园豆:30
tea2007 | 园豆:62 (初学一级) | 2025-01-07 19:25
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册