Angular 结构指令:用另一个组件包装宿主元素

Posted

技术标签:

【中文标题】Angular 结构指令:用另一个组件包装宿主元素【英文标题】:Angular structural directive: wrap the host element with some another component 【发布时间】:2018-05-01 21:46:55 【问题描述】:

我有最简单的 Angular 结构指令:

import  Directive, TemplateRef, ViewContainerRef  from '@angular/core';

@Directive( selector: '[hello]' )
export class HelloDirective 
  constructor(
    private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) 
      this.viewContainer.createEmbeddedView(this.templateRef);
  

我是这样用的:

<div *hello>Hello Directive</div>

它按预期向我显示“Hello Directive”消息。现在我想通过用另一个组件包装来更改内容:

<my-component>Hello Directive</my-component>

我希望指令为我做这件事。我知道我可以使用组件范例并创建HelloComponent 而不是HelloDirective 并使用ng-template 等与templatetemplateUrl 属性在@Component 装饰器上定义的模板... 但是有吗一种可以与指令范式一起使用的方法来实现这样的结果?

【问题讨论】:

是否要将指令的内容嵌入到组件中? @yurzui 是的,然后将结果传递给初始模板而不是指令的内容。这样它就可以在末尾被解释为&lt;div *hello&gt;&lt;my-component&gt;Hello Directive&lt;/my-component&gt;&lt;/div&gt;(而不是&lt;div *hello&gt;Hello Directive&lt;/div&gt;)。 my-component 是否包含ng-content @yurzui 它可以完全定制以提供正确的行为。此任务中的my-component 实现没有限制。 【参考方案1】:

您可以动态创建组件并将可投影节点传递给它。所以它可能看起来像

@Directive( selector: '[hello]' )
export class HelloDirective implements OnInit, DoCheck 
  templateView: EmbeddedViewRef<any>;
  constructor(
      private templateRef: TemplateRef<any>,
      private viewContainer: ViewContainerRef,
      private resolver: ComponentFactoryResolver) 
  

  ngOnInit() 
    this.templateView = this.templateRef.createEmbeddedView();
    const compFactory = this.resolver.resolveComponentFactory(MyComponent);
    this.viewContainer.createComponent(
      compFactory, null, this.viewContainer.injector, [this.templateView.rootNodes])
  

  ngDoCheck(): void 
    if (this.templateView) 
        this.templateView.detectChanges();
    
  

您必须将MyComponent 添加到@NgModuleentryComponents 数组中

完整示例可在 Stackblitz

上找到

另见

Creating a angular2 component with ng-content dynamically

【讨论】:

如果我在 hello 指令中使用嵌套组件,它就不起作用。你有解决这个问题的建议吗:stackblitz.com/edit/angular-97ckey?embed=1&file=app/… @MuratÇorlu 你的意思是 hello 组件没有得到输入吗?那是因为它的视图不是角度变化检测树的一部分。试试这个stackblitz.com/edit/angular-jrtnmn?file=app/app.component.ts 太好了,谢谢。另一个问题是,现在 hello 指令中的 hello 组件在指令嵌入内容时正在初始化,但在删除内容时不会销毁:stackblitz.com/edit/… 你是否也有建议在我们从 dom 中删除内容时销毁 hello 组件? @yurzui 我有一个来自 devextreme 的 dx-text-box,并且代码无法正常工作,在我解决了这个问题后我更新了你的答案(因为许多开发人员复制粘贴并且他们希望它能够解决的盒子)

以上是关于Angular 结构指令:用另一个组件包装宿主元素的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2:指令和宿主组件之间的通信

在 Angular 结构指令中使用动态组件会产生额外的 HTML 标记。如何删除或更换它?

在 angular2 中构建一个包装器指令(包装一些内容/组件)

Angular2:用组件的模板替换宿主元素

Angular 组件宿主元素的宽度和高度为 0

移除 Angular 组件创建的宿主 HTML 元素选择器