Angular:在ngTemplateOutlet递归列表中访问父指令
解决Angular模板渲染嵌套列表时子指令获取父指令实例的问题
问题原因
使用ngTemplateOutlet渲染嵌套结构时,模板内容的注入上下文是模板定义的位置,而非插入位置。这导致子MyDirective通过@Optional() @SkipSelf()无法找到父级指令实例——父指令不在子指令的注入器层级中。
解决方案:手动传递父指令实例到模板上下文
通过在模板上下文里显式传递当前指令实例,让子模板能拿到父级指令引用,具体步骤如下:
1. 修改HTML模板,传递父指令上下文
<ul> <!-- 新增let-parentDirective="parent"接收父指令参数 --> <ng-template #itemTemplate let-entry let-parentDirective="parent"> <li myDirective [parentItem]="parentDirective">{{ entry.label }} <ng-container *ngIf="entry.children && entry.children.length"> <ul> <ng-container *ngFor="let child of entry.children"> <!-- 渲染子元素时,将当前myDirective传入context的parent字段 --> <ng-template *ngTemplateOutlet="itemTemplate; context: { $implicit: child, parent: myDirective }"></ng-template> </ng-container> </ul> </ng-container> </li> </ng-template> <ng-container *ngFor="let item of tree"> <!-- 根节点无父指令,传入null --> <ng-template *ngTemplateOutlet="itemTemplate; context: { $implicit: item, parent: null }"></ng-template> </ng-container> </ul>
2. 修改MyDirective,通过Input接收父实例
import { Directive, Input, Optional, SkipSelf } from '@angular/core'; @Directive({ selector: '[myDirective]' }) export class MyDirective { private _parentItem: MyDirective | null = null; // 通过Input接收手动传递的父指令实例 @Input() set parentItem(parent: MyDirective | null) { this._parentItem = parent; } get parentItem(): MyDirective | null { return this._parentItem; } // 保留原依赖注入方式作为降级方案(非模板渲染场景仍可用) constructor(@Optional() @SkipSelf() fallbackParent?: MyDirective) { if (fallbackParent) { this._parentItem = fallbackParent; } } }
效果验证
完成上述修改后,F1-1-0对应的MyDirective实例的parentItem属性,就能直接指向F1-1对应的父指令实例,完美解决模板渲染时依赖层级丢失的问题。
内容的提问来源于stack exchange,提问作者Mike5
相关产品推荐
相关产品推荐

