【问题标题】:How to create directive that removes other directives before they happen in Angular如何创建指令以在其他指令在 Angular 中发生之前删除它们
【发布时间】:2020-07-04 07:29:50
【问题描述】:

我正在尝试制定一个指令来阻止另一个指令触发。我尝试同时使用结构性和非结构性指令来实现这一点,但它们都没有奏效。

我正在使用的简单 html:

<p appRemover appColor>
  Start editing to see some magic happen :)
</p>

假设我有一个颜色指令,它只是将它应用到的元素的颜色属性更改为红色。这是颜色指令的代码:

constructor(private el: ElementRef) {}

  ngAfterViewInit(): void {
    this.el.nativeElement.style.color = 'red'
  }

我将创建另一个指令,remover-directive,它将执行以下操作:

constructor(private el: ElementRef, private ren: Renderer2) { }

  ngAfterViewInit(): void {
    this.ren.removeAttribute(this.el.nativeElement, 'appColor');
  }

这里的想法是我可以简单地在渲染之前从元素中删除指令。在删除 appColor 属性后打印 el.nativeElement 后,看起来该属性已消失,但颜色已变为红色。理想情况下,卸妆指令会在颜色指令之前触发,但我似乎无法找出 Angular 是如何选择顺序的。

我什至尝试了一个结构指令来解决这个问题:

constructor(private vc: ViewContainerRef, private template: TemplateRef<any>, private ren: Renderer2) { }

  ngOnInit() {
    this.ren.removeAttribute(this.template.elementRef.nativeElement, 'appColor');
    this.vc.createEmbeddedView(this.template);
  }

但这实际上会引发一个错误,说 el.removeAttribute 不是一个函数?

是否有一个既定的模式可用于使用指令来删除或阻止同一元素上的另一个指令触发?如果没有,有没有办法真正做到这一点?

【问题讨论】:

  • 你为什么要这样做?为什么你不能让你的appColor在某些条件下决定做某事?
  • 我试图有条件地渲染的指令在一个导入的库中,所以我不能对它进行这样的更改

标签: css angular attributes directive angular2-directives


【解决方案1】:

在 Angular 中,无论如何您都无法动态创建/删除指令 (Github Issue)。如果它是导入的库,您需要将其分叉并生成例如 @Input() disabled 到该指令,因此当它处于活动状态时它不会触发事件(当然您也需要执行该逻辑)。

【讨论】:

  • 这可以通过创建一个新组件来实现,该组件接受布尔输入是否显示指令以及模板,并且组件将使用 ngswitch 仅呈现模板或带有指令的模板?
【解决方案2】:

据我所知,您不能有条件地删除指令。相反,您可以做的是拥有两个版本的元素,一个带有指令,一个没有指令,然后使用*ngIf... else 选择适当的元素。为避免重复元素的内部内容,请在通用模板中声明该内容,然后插入 ngTemplateOutlet

<!-- Container element with the appColor directive -->
<p *ngIf="useColorDirective; else noColorDirective" appColor>
  <ng-container *ngTemplateOutlet="content"></ng-container>
</p>

<!-- Alternate container element, without the directive -->
<ng-template #noColorDirective>
  <p><ng-container *ngTemplateOutlet="content"></ng-container></p>
</ng-template>

<!-- Common content of the container elements -->
<ng-template #content>
  The inner content is here...
</ng-template>

请参阅this stackblitz 以获取演示。


如果您想在多个地方重用该技术,您可以将代码包装在一个组件中:

@Component({
  selector: 'app-p',
  ...
})
export class AppParagraphComponent {
  @Input() useColor = true;
}
<p *ngIf="useColor; else noColorDirective" appColor>
  <ng-container *ngTemplateOutlet="content"></ng-container>
</p>
<ng-template #noColorDirective>
  <p><ng-container *ngTemplateOutlet="content"></ng-container></p>
</ng-template>
<ng-template #content>
  <ng-content></ng-content>
</ng-template>

然后可以用作:

<app-p [useColor]="useColorDirective">
  This is the content!!!
</app-p>

有关演示,请参阅 this stackblitz。您可能需要为可以有条件地应用颜色指令的每种类型的元素定义一个不同的组件。

【讨论】:

  • 这似乎是一个很好的解决方案,除了我试图有条件地更改的指令可以在

    s 以外的元素上。是不是有一些内容投影的想法,我可以将这个解决方案与我想要的东西结合起来?

  • 我在答案中添加了一个包含在组件中的代码示例。但是,您可能需要定义其中的几个,每个元素类型一个。
猜你喜欢
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2014-04-02
相关资源
最近更新 更多