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

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

Getting templateRef of host component in directive

问题

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

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

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

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

Usage:

  1. <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

  1. &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)

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

Usage:

  1. &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

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

  1. export class Directive1Directive implements AfterViewInit {
  2. constructor(@Host() @Self() private host: Component1Component) {}
  3. ngAfterViewInit(): void {
  4. console.log(this.host.templateRef);
  5. }
  6. }

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

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

  1. export abstract class BaseComponent {
  2. public templateRef?: TemplateRef<any>;
  3. }

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

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

指令基本上没有改变。

  1. export class Directive1Directive implements AfterViewInit {
  2. constructor(private host: BaseComponent) {}
  3. ngAfterViewInit(): void {
  4. console.log(this.host.templateRef);
  5. }
  6. }

本回答的很多内容都来自 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:

  1. export class Directive1Directive implements AfterViewInit {
  2. constructor(@Host() @Self() private host: Component1Component) {}
  3. ngAvterViewInit(): void {
  4. console.log(this.host.templateRef);
  5. }
  6. }

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.

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

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.

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

The directive is basically unchanged.

  1. export class Directive1Directive implements AfterViewInit {
  2. constructor(private host: BaseComponent) {}
  3. ngAvterViewInit(): void {
  4. console.log(this.host.templateRef);
  5. }
  6. }

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

答案2

得分: 0

  1. 如果你尝试在 `ngOninit` 中获取它,你必须将其声明为静态的:
  2. ```typescript
  3. @ViewChild('content', { static: true }) public templateref: TemplateRef<any>;

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

  1. <details>
  2. <summary>英文:</summary>
  3. If you try getting it in `ngOninit`, you have to declare it as static :
  4. ```typescript
  5. @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:

确定