【问题标题】:Conditionally apply click event in Angular 4在Angular 4中有条件地应用点击事件
【发布时间】:2018-02-09 14:53:40
【问题描述】:

是否可以在模板中定义附加点击处理程序的条件?

例如,我能得到的最接近的方法是在 click 方法的入口处评估条件。

<a class='user' (click)=" isOverflown? menu.toggle($event): '' "></a>

如果标志 isOverflown 为 false,是否有办法完全避免绑定到 click 事件?

另外,我不想在元素上使用ng-if 并复制模板。即:创建一个具有click 绑定的元素并创建另一个没有绑定的元素,然后使用ng-if 显示/隐藏它们

【问题讨论】:

  • 没有办法启用/禁用绑定。您可以使用@ViewChild('.user') aUser:ElementRef;,然后使用this.aUser.nativeElement.addEventListener(...);removeEventListener()
  • 当您想避免绑定时,您究竟想达到什么目的?为什么绑定对您有问题?
  • 我有一个组件,其中只有当用户为@Input 之一提供值时才需要点击行为。所以,我只知道这两种方式,其中我不想使用ng-if ,因为大模板是重复的。所以,我想知道如果不满足条件,是否有一种声明方式根本不注册处理程序。这是否解释了我在尝试什么?
  • 只要在方法的开头加上if (!isOverflown) {return},就可以达到同样的效果。
  • @Pac0 不是说特殊情况,但总的来说,事件监听器是一种你更喜欢少而不是多的东西。你想尽可能晚地附加它们,尽可能早地解除附加,如果你不需要它们就不要使用它们。它不仅仅是关于在侦听器方法中处理的最终效果,它与附加侦听器方法有关。因此,他正在寻找一种方法,除非他需要,否则不会拥有它。这是一个很好的做法。

标签: angular


【解决方案1】:

你可以这样做

<a class='user' (click)="isOverflown && menu.toggle($event)"></a>

【讨论】:

  • 这是一个很好的答案和解决方案
  • 简单而出色的答案
  • 这是否还没有将事件监听器添加到元素中?
  • @ZakiMohammed 你错了,当你添加一个像监听器这样的条件时,它仍然被添加,但是当第一个条件评估为 false 时它永远不会被执行。所以它不会调用该方法,但仍会绑定一个事件处理程序。
  • 由于@Wilt 所说,这样的事情不会按预期工作:this.onToggle.observers.length &gt; 0。由于仍然创建了侦听器,即使它永远不会调用您的方法。
【解决方案2】:

没有办法启用/禁用绑定。

强制执行是可能的

@ViewChild('.user') aUser:ElementRef; 

clickHandler(event) {
  console.log(event);
}
_clickHandler = this.clickHandler.bind(this);

ngAfterViewInit() {
  this.aUser.nativeElement.addEventListener('click', this._clickHandler); 
}  

退订使用

this.aUser.nativeElement.removeEventListener('click', this._clickHandler); 

另见Dynamically add event listener in Angular 2

【讨论】:

  • removeEventListener 在您的代码中不起作用,因为bind 方法会创建新函数
  • Renderer.listen 返回函数,我们可以调用它来取消订阅
  • 好的,听起来不错。你认为我更新的答案会起作用吗?
【解决方案3】:

我建议您编写一个执行条件操作的处理程序,这是恕我直言的最简单方法:

在组件模板中:

<a class='user' (click)="myClickHandler($event)"></a>

在组件代码 .ts 中:

myClickHandler(event): void {
  if (this.isOverflown) {
    this.menu.toggle(event);
  }
}

评论后编辑:如果您真的想避免绑定(我不明白为什么,但无论如何),您可以使用*ngIf 拥有一个条件组件:

<a class='user' *ngIf="isOverflown" (click)="menu.toggle($event)"></a>
<a class='user' *ngIf="!isOverflown"></a>

【讨论】:

  • 是的,这和我在模板中所做的一样好。但我想知道是否可以避免绑定到该方法。
  • 在这种情况下,您可以使用*ngIf。我将编辑我的答案。
  • 大声笑,我刚刚编辑了问题,我不想在模板中复制大元素。我放的例子很简约,实际上我有一个精心制作的模板。
  • 好吧,我以前不知道。我现在不知道任何答案,那么。请问你为什么不想要绑定?这似乎是 Angular 要走的路。闻起来像an XY Problem
  • 所以,似乎只有这两种干净的方式。
【解决方案4】:

有一个类似的问题,这对我有用:

<p (click)="item.isClickable ? item.onClick() : return;">
 Hello Mom!
</p>

【讨论】:

  • 您仍然在 p 标签上添加了点击事件。
【解决方案5】:

您需要将ElementRefRenderer 注入到您的组件中,并在感兴趣的元素引用上使用其listen 方法。

https://angular.io/api/core/Renderer

https://angular.io/api/core/Renderer2

this.renderer.listen(this.elementRef.nativeElement, 'click', callbackFunction)

【讨论】:

  • 似乎没有办法使用Renderer.listen 删除事件处理程序,也许使用invokeElementMethod(this.elementRef.nativeElement, 'addEventListener', ['click', this.clickHandler.bind(this)])
  • Yurziu 在我的答案下方的 cmets 中解释了它。
  • 是的,你只需调用listen返回的函数。加上一个,现在有一个 Renderer2。
  • 我已经看到Renderer2 几个月了,但从来没有看到任何解释为什么除了Renderer 之外还添加了它。
  • 好吧,如果我们计算 docs/codebase 中所有缺少解释的东西,那会让我们度过一个漫长的夜晚;)
【解决方案6】:

在三元运算符的帮助下绑定 null 并添加禁用类解决了我的问题。

<a (click)="item.quantity>1 ? decreaseQuantity():null;" [ngClass]="{'disabled': item.quantity<=1}">

【讨论】:

  • Bootstrap disabled 类已经阻止了点击。无需使用角度来防止点击。尽管这是最不受欢迎的答案,但只要项目中存在 Bootstrap,这种方法是解决问题的最简单方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-11
相关资源
最近更新 更多