我可以一次在结构指令中同时做两件事吗?

时间:2018-11-15 18:00:14

标签: angular angular-directive

我想创建一个结构指令,其行为如下:

<p *myDirective="condition">This is some text</p>
  • 如果conditionfalse,则{strong>完全不呈现<p>标签。
  • 如果conditiontrue,则<p>标签将带有额外的class属性。

因此,要么没有呈现任何内容,要么:

<p class="my-added-class">This is some text</p>

换句话说,它有点像*ngIf,但有其他行为。

我可以找到有关如何执行包含/排除行为的示例(实际上有一个示例in the Angular docs)。我还可以找到有关如何向元素using the Renderer2 API添加类的示例。

但是,我看不到如何结合使用这些技术,因为第一种方法操纵viewContainer来创建嵌入的 view ,而第二种方法使用渲染器来操纵一个元素

有没有办法做到这一点?我可以以某种方式创建嵌入式视图,然后操纵其创建的元素吗?还是可以操纵模板来更改视图的呈现方式?

[注意:@HostBinding不适用于结构化指令,因此这不是一个选择]

2 个答案:

答案 0 :(得分:2)

当它满足传递给它的表达式(在setter内部)时,我会考虑在DOM上添加类。您可以抓住指令中的ElementRef依赖项,并向其添加一个class,这是正确的。

@Input() set myDirective(condition: boolean) {
  if (condition) {
    this.viewContainer.createEmbeddedView(this.templateRef);
    this.elementRef.nativeElement.nextElementSibling.classList.add('my-added-class'); // renderer API can be used here
    // as Alex and Yurzui suggested
    // const view = this.viewContainer.createEmbeddedView(this.templateRef); 
    // view.rootNodes[0].classList.add('some-class')
  } else if (condition) {
    this.viewContainer.clear();
  }
}

答案 1 :(得分:1)

另一种方式

只是玩耍而已:)

使用Renderer2是通用的

import {
  Directive,
  Renderer2,
  TemplateRef,
  ViewContainerRef,
  ElementRef,
  Input, OnInit } from '@angular/core';

@Directive({
  selector: '[appMy]'
})
export class MyDirective implements OnInit{
  constructor(
  private templateRef: TemplateRef<any>,
  private viewContainer: ViewContainerRef,
  private renderer: Renderer2) { }
  @Input() set appMy(condition: boolean) {
   if (condition) {
     this.viewContainer.createEmbeddedView(this.templateRef);
    } else  {
     this.viewContainer.clear();
   }
  }
  ngOnInit() {
    const elementRef = this.viewContainer.get(0).rootNodes[0] as ElementRef;
    this.renderer.addClass(elementRef, 'myclass');
  }
}

遵循@Pankaj方式,但使用渲染器

@Input() set appMy(condition: boolean) {
   if (condition) {
     const view = this.viewContainer.createEmbeddedView(this.templateRef);
     this.renderer.addClass(view.rootNodes[0], 'myclass');
   } else  {
     this.viewContainer.clear();
   }
  }