【问题标题】:Structural directive - finding the element it is placed on结构指令 - 找到它所在的元素
【发布时间】:2017-05-09 00:25:42
【问题描述】:

使用结构指令,我如何获得指令所在的(本机)元素? 使用普通指令,ElementRef 有它的 nativeElement 指向它 - 例如:

<input type="text" example>

@Directive({
  selector: '[example]'
})
export class ExampleDirective {    

  constructor( private el: ElementRef) {}

  ngAfterViewInit() {
    console.log(this.el.nativeElement); // the input
  }
}

但是使用结构指令,它指向模板注释 - 例如。

<input type="text" *example>

@Directive({
  selector: '[example]'
})
export class ExampleDirective {

  constructor(
    private el: ElementRef,
    private view: ViewContainerRef,
    private template: TemplateRef<any>
  ) {}

  ngAfterViewInit() {
    this.view.createEmbeddedView(this.template);

    console.log(this.el.nativeElement); // template bindings comment
    // how to find the input itself?
  }
}

我尝试过使用 ViewContainerRef、TemplateRef、@ContentChild、@ViewChild 的各种组合 - 只是似乎无法找到输入元素本身...

【问题讨论】:

标签: angular


【解决方案1】:

所有结构指令都添加到&lt;ng-template&gt; 元素。 Angular 从不向 DOM 添加 &lt;ng-template&gt; 元素。因此无法获取添加了结构指令的元素。

如果您使用带有* 的简写语法,则喜欢

<div *ngIf="..."></div>

角度创建

<ng-template [ngIf]="...">
  <div></div>
</ng-template>

因为&lt;ng-template&gt; 没有被添加,所以没有办法得到它,而且因为&lt;div&gt; 不是结构指令被添加到的元素,你也不能使用指令引用来获取这个元素。

【讨论】:

  • 感谢 Gunter - 我开始认为情况就是这样。我知道 angular 如何将结构指令扩展为模板,我只是希望对所使用的元素仍有一些可用的参考 - 看起来不是那样的。似乎是一个过度的网站。我可以看到输入元素(在 TemplateRef 的 nextSibling 下) - 但没有以一种很好的可获取方式。
  • 如果您能详细说明一下您尝试解决的实际问题是什么,可能会发现一些替代方法。
  • 你可以用 queryAllNodes stackoverflow.com/a/57796556/2145997 来做,但是你的指令必须在测试模块中定义
  • @s-f 感谢您的来信。看起来这仅适用于测试,但不适用于应用程序代码。
【解决方案2】:

这不漂亮,但对我有用:

this.viewContainer.get(0).rootNodes[0]

我在实现 *ngIf 指令的一个版本但带有动画时使用它:animatedIf

【讨论】:

  • 这并不理想,但我们有类似的情况,因为他们最近将评论移到了节点插入之后,所以我们的旧代码坏了。这很有效,谢谢:) 注意:(this.viewContainer.get(0) as any).rootNodes[0] 以避免输入错误
【解决方案3】:

HTMLElement 上使用结构指令时,您将无法获得对该元素的引用,因为它尚未呈现。当您尝试在代码console.log(this.el.nativeElement); // template bindings comment 中访问它时,input text box 尚未呈现

请参阅下面的链接以了解 Angular 中的结构指令是如何工作的。 https://angular.io/guide/structural-directives#the-asterisk--prefix

所以要获取元素的引用,你可以在同一个元素上使用attribute directive 并做需要的事情。

【讨论】:

    【解决方案4】:

    基于Structural Directives Documentation(不确定它是否有效,但可能对您有所帮助):

    <input type="text" *example>
    
    
    @Directive({
      selector: '[example]'
    })
    export class ExampleDirective {
    
      constructor(private viewContainer: ViewContainerRef) { }
    
      @Input() set example() {
        console.log(this.viewContainer.element.nativeElement.value);
      }
    }
    

    【讨论】:

    • 感谢@lenny,但我确实尝试过这种方式 - 希望它会起作用,但它不会 - 你会得到一个未定义的(在你的例子中)this.input - 所以没有可用的nativeElement。
    • @CalvJ 抱歉,我之前的回答是错误的。我更新了它,不确定它是否有效,但也许对你有帮助。
    • :-) 再次感谢 - 但是 (this.viewContainer.element.nativeElement) 仍然会抓住你的评论!我认为也许 Gunter 是正确的,并且没有直接的方法来掌握它。
    猜你喜欢
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多