获取宿主组件的模板引用在指令中

huangapple go评论58阅读模式
英文:

Getting templateRef of host component in directive

问题

Component1: 我有一个组件,其中包含ng-template和其下的内容

<ng-template #content><ng-content></ng-content></ng-template>

Directive: 在我的指令中,我尝试获取templateRef,但它总是为空。 (在ViewInit和ContentAfterInit中都尝试过) (我必须将这个模板引用传递给一个服务,以便打开模态框)

@ViewChild('content') public templateref: TemplateRef<any>;

Usage:

<app-component1 directive1> <app-anothercomponent>.....<app-component2> .... </app-component1>

是否有可能在指令中获取ng-template的内容?
Slackblitz链接:https://stackblitz.com/edit/angular-directive-view-children-y59xnh?file=app%2Finput-overview-example.html

英文:

Component1: I have a component that has ng-template and content under it

&lt;ng-template #content&gt;&lt;ng-content&gt;&lt;/ng-content&gt;&lt;/ng-template&gt;

Directive: In my directive, I am trying to get templateRef, but it's always empty. (Tried in ViewInit and ContentAfterInit both) (I have to pass this template ref to a service in order to open the modal)

@ViewChild(&#39;content&#39;) public templateref: TemplateRef&lt;any&gt;;

Usage:

&lt;app-component1 directive1&gt; &lt;app-anothercomponent&gt;.....&lt;app-component2&gt; .... &lt;/app-component1&gt;

Is it even possible to get ng-template content in the directive?
Slackblitz: https://stackblitz.com/edit/angular-directive-view-children-y59xnh?file=app%2Finput-overview-example.html

答案1

得分: 1

我认为您正在询问如何从指令的宿主组件中获取 TemplateRef

如果您预先知道组件的类型,那么您可以直接从指令中引用它:

export class Directive1Directive implements AfterViewInit {
  constructor(@Host() @Self() private host: Component1Component) {}

  ngAfterViewInit(): void {
    console.log(this.host.templateRef);
  }
}

如果您不知道预期的宿主组件类型,情况就会变得更加复杂。通用地将宿主组件注入到指令的最佳方法是让宿主指令实现一个类,并将该组件提供为该类。

您可以首先创建一个具有您想要引用的宿主组件的所有属性的类。在这种情况下,我们只声明了一个公开 TemplateRef 的属性。之所以使用类而不是接口的唯一原因是它减少了使用 InjectionToken 的需要。

export abstract class BaseComponent {
  public templateRef?: TemplateRef<any>;
}

宿主组件中唯一需要注意的是,我们需要在其提供者数组中添加一个提供者,该提供者基本上在 BaseComponent 的别名下“重新提供”了自身。函数 forwardRef 用于创建对稍后声明的内容的延迟引用。

@Component({
  /*...*/
  providers: [{ provide: BaseComponent, useExisting: forwardRef(() => Component1Component) }]
})
export class Component1Component implements BaseComponent {
  @ViewChild('content') public templateRef?: TemplateRef<any>;
}

指令基本上没有改变。

export class Directive1Directive implements AfterViewInit {
  constructor(private host: BaseComponent) {}

  ngAfterViewInit(): void {
    console.log(this.host.templateRef);
  }
}

本回答的很多内容都来自 How You Can Access All Host Component Details Inside the Directive in Angular

英文:

What I think you're asking is how do I get a TemplateRef from a Directive's host Component?

If you know the component's type in advance, then you can reference it directly from the directive:

export class Directive1Directive implements AfterViewInit {
  constructor(@Host() @Self() private host: Component1Component) {}

  ngAvterViewInit(): void {
    console.log(this.host.templateRef);
  }
}

It becomes more tricky if you don't know the expected host component's type. The best way to generically inject a host component into a directive is to have that host directive implement a class and provide that component as that class.

You can start by creating a class that has all properties from the host component that you want to reference. In this case we're just declaring property that exposes the TemplateRef. The only reason why a class is used over an interface is that it reduces the need for using an InjectionToken.

export abstract class BaseComponent {
  public templateRef?: TemplateRef&lt;any&gt;;
}

The only wrinkle in the host component is that we need to a provider is added to its providers array that basically "reprovides" itself under the alias of BaseComponent. The function forwardRef is used to create a deferred reference to something declared later.

@Component({
  /*...*/
  providers: [{ provide: BaseClass, useExisting: forwardRef(() =&gt; Component1Component ) }]
})
export class Component1Component implements BaseComponent {
  @ViewChild(&#39;content&#39;) public templateRef?: TemplateRef&lt;any&gt;;
}

The directive is basically unchanged.

export class Directive1Directive implements AfterViewInit {
  constructor(private host: BaseComponent) {}

  ngAvterViewInit(): void {
    console.log(this.host.templateRef);
  }
}

A lot of this answer came from How You Can Access All Host Component Details Inside the Directive in Angular.

答案2

得分: 0

如果你尝试在 `ngOninit` 中获取它,你必须将其声明为静态的:

```typescript
@ViewChild('content', { static: true }) public templateref: TemplateRef<any>;

否则它只能在视图初始化后才可用 (ngAfterViewInit)。除此之外,这是可能的,并且经常这样做,所以如果你在这方面遇到问题,试着在 stackblitz 上创建一个 MCVE 来展示你的问题。


<details>
<summary>英文:</summary>

If you try getting it in `ngOninit`, you have to declare it as static : 

```typescript
@ViewChild(&#39;content&#39;, { static: true }) public templateref: TemplateRef&lt;any&gt;;

Otherwise it' only avilable after view init (ngAfterViewInit). Other than that, it is possible and done very often, so if you have an issue doing it, try making a MCVE on stackblitz showing your issue.

huangapple
  • 本文由 发表于 2023年6月27日 20:00:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76564647.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定