如何从指令获取角度视图层次?

时间:2018-10-30 18:00:38

标签: angular typescript

Angular版本6 +

我正在研究一个指令,该指令可以放置在任何元素上以用于常规用法日志记录。对于上下文,它看起来类似于以下内容:

@Directive({
  selector: '[log]'
})
export class LogDirective {
  @Input() log: string; // the log message
  @Input() logOn: string; // event name to trigger logging

  constructor(private renderer: Renderer2,
              private elementRef: ElementRef) {
  }

  ngOnInit() {
    this.renderer.listen(this.elementRef.nativeElement, this.logOn, () => {
      // log the message, etc.
    }
  }
}

<div log="Clicked the element" logOn="click">Click Me</div>

这很好用,但是我认为自动获取某种类型的父级层次结构以便进行记录会很酷。这样,某人可以查看日志,并很容易看到它的记录位置。类似于“ AppComponent-> SomeOtherComponent-> ParentCompnent”。可以向该指令注入一些东西,以确定它在视图层次结构中的位置吗?

2 个答案:

答案 0 :(得分:1)

您可以将ViewContainerRef注入指令以访问托管组件。 然后,您可以使用它来读取当前组件和该组件的父组件。

如此递归将为您带来所追求的结果。

类似这样的东西(我将递归算法留给您):

constructor(private viewContainerRef: ViewContainerRef) { }

private clicked() {
    console.log(this.viewContainerRef['_view'].component);
    console.log(this.viewContainerRef['_view'].parent.component);
    console.log(this.viewContainerRef['_view'].parent.parent.component);
  }

(1) Stackblitz demo

(1)忽略该应用程序的其余部分,我在Google上搜索了某人的“角度指令模板”,并对其进行了更改以使其快速获取

(2)当然,免责声明:“您不应该在角度上阅读_attributes,因为它可以在将来的版本中进行更改而无需通知,并且您将不支持它们”等等等。

答案 1 :(得分:0)

根据Web规范中的自定义DOM元素。标记名称必须包含连字符,并且用作名称空间分隔符。这是将来对Web组件进行校对所必需的,这样它们就不会与将来的HTML更改发生冲突。

因此,任何具有连字符的父DOM元素都是一个组件。假定所有自定义元素都是Angular组件,并且您的Angular项目按照准则使用前缀。

您可以使用类似这样的函数来生成前缀。

function getPrefix() {
    let el = this.elementRef.native;
    let names = [];
    while (el) {
        if(el.tagName.indexOf("-") !== -1) {
           names.unshift(el.tagName);
        }
        el = el.parentNode;
    }
    return names.join(' -> ');
}

然后记录以下消息:

ngOnInit() {
   this.renderer.listen(this.elementRef.nativeElement, this.logOn, () => {
      const prefix = this.getPrefix();
      console.log(prefix + ' the message here');
   }
}