在Angular中,当复选框有改变事件时如何阻止TR点击事件的传播(stopPropagation())?

5

我正在使用Angular 6。我有一个带有点击事件的表格行(<TR>)。为了测试目的,让我们假设该事件将“quack!”打印到控制台。以下是HTML:

<tr *ngFor="let t of things" (click)="quack()">
  ...
</tr>

在组件中:
quack() {
  console.log('quack!');
}

现在,在这一行中我有一个复选框。它是Bootstrap 4的自定义复选框,但我认为这与我需要解决的问题无关。该复选框具有一个自定义指令,该指令添加了一个change事件处理程序(而不是click事件)。HTML的简化版本如下:
<tr *ngFor="let t of things" (click)="quack()">
  ...
  <div class="custom-control custom-checkbox">
    <input type="checkbox" class="custom-control-input" id="cb{{t.id}}" name="cb{{t.id}}" 
     [my-directive]="b.somedata">
    <label class="custom-control-label" for="cb{{t.id}}">&nbsp;</label>
  </div>
  ...
</tr>

在my-directive指令代码中:
@HostListener('change') onChange() {
  // do some stuff...
}

问题

我希望在任何人点击该行时,quack()函数都会触发,除非他们点击复选框。当他们选中或取消选择复选框时,我希望自定义指令中的onChange()函数被触发,并且我不想要quack声。

每次单击行时,控制台上都会出现“quack!”,这是正确的。但是奇怪的是,当我单击复选框时,会出现两个 quack 声,然后onChange()处理程序才会触发。 我想要零个quack声,我预期只会有一个,但是我得到了两个!

  • 顺便说一句,当我通过按空格键而不是点击来选中/取消选中复选框时,仍然会得到一个 quack。我无法想象单击事件来自哪里。

我在 <input>元素中添加了 (click)="$event.stopPropagation();",以此来解决这个问题。当我单击复选框时,这使我只得到一个 quack 。但是我希望得到零个quack声。 我该如何防止单击复选框传播触发 quack()click()事件?

  • 顺便说一句,在添加了该代码片段后,使用空格键切换复选框会产生零个quack声。

我没有完全阅读,但当Angular调用其自定义的(click)事件时,浏览器事件已经传播,因此您无法停止它。但是,您仍然可以通过使用纯JavaScript创建自己的点击事件来停止点击事件。 - Ploppy
@Ploppy - 你确定吗?我认为你可以在(click)事件处理程序中停止传播。 - ConnorsFan
1
您可以查看此StackBlitz。如果我们在指令中处理click事件并停止其传播,它似乎可以工作。注意:在我的代码示例中,我确保每个复选框的idname是唯一的(但即使没有这种更改,单击管理也可以正常工作)。 - ConnorsFan
你尝试过使用event.preventDefault()或者在事件中返回false来阻止浏览器的默认行为吗? - Nour
1
这个不同的stackblitz中,我在复选框的(click)事件处理程序中停止了事件传播。 - ConnorsFan
1
@ConnorsFan,我修改了示例代码以显示每个复选框的唯一ID/名称,正如您建议的那样。我的问题实际上是由于Bootstrap 4自定义复选框引起的;您的解决方案对于任何普通复选框都非常有效。 - workerjoe
1个回答

13

答案

我错误地假设它是Bootstrap 4自定义复选框无关紧要--实际上这是我的问题的关键。在这种使用Bootstrap 4的情况下,<input>本身是不可见的!你在屏幕上看到的像复选框的东西实际上是由CSS生成的。所以click事件首先不属于那个<input>元素。

为了解决这个问题,我将(click)="$event.stopPropagation();"移动到包装自定义复选框的<div>元素中,如下所示:

<tr *ngFor="let t of things" (click)="quack()">
  ...
  <div class="custom-control custom-checkbox" (click)="$event.stopPropagation();">
    <input type="checkbox" class="custom-control-input" id="cb{{t.id}}" name="cb1" 
     [my-directive]="b.somedata">
    <label class="custom-control-label" for="cb{{t.id}}">&nbsp;</label>
  </div>
  ...
</tr>

如果我使用的是普通的复选框而不是这些Bootstrap 4定制的复选框,那么ConnorsFan提到的任何一种解决方案都可以完美地运行。

感谢你的 stopPropagation() 帮助! - mohsenmadi
1
我曾经遇到过custom-checkbox的同样问题,为了解决这个问题,我使用了简单的复选框。你的回答让我可以再次使用custom-checkbox。谢谢! :) - marioosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接