Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Angular, how to stopPropagation() of TR click event when checkbox has change event?

I'm using Angular 6. I have a table row (<TR>) with a click event. For testing purposes let's just say the event prints "quack!" to the console. This is the HTML:

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

In the component:

quack() {
  console.log('quack!');
}

Now, within this row I have a checkbox. It's a Bootstrap 4 custom checkbox but I don't think that's material to the problem I need to solve. That checkbox has a custom directive which adds a change event handler (not a click event). A simplified version of the HTML is:

<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>

In the my-directive directive code:

@HostListener('change') onChange() {
  // do some stuff...
}

The problem

What I want to happen is for the quack() function to fire when anyone clicks on the row, unless they click the checkbox. When they check or uncheck the checkbox, I want the onChange() function in the custom-directive to fire, and I want no quacking.

The "quack!" appears in the console once each time I click on the row, which is correct. What's odd is that when I click on the checkbox I get two quacks and then the onChange() handler fires. I'd like zero quacks, I expected one, but I got two!

  • Incidentally, when I check/uncheck the checkbox by hitting the spacebar instead of clicking, I still get one quack. I can't imagine where the click event comes from.

I added (click)="$event.stopPropagation();" to the <input> element, thinking this would solve the problem. It brings me down to just one quack when I click on the checkbox. I'd like to get to zero. How can I prevent the click on the checkbox from propagating a click() event that triggers a quack()?

  • By the way, after adding that snippet, toggling the checkbox with spacebar produces zero quacks.
like image 409
workerjoe Avatar asked Aug 16 '18 20:08

workerjoe


1 Answers

The Answer

I was wrong to assume that it being a Bootstrap 4 custom checkbox was immaterial -- in fact that was the key to my problem. In this usage of Bootstrap 4, the <input> itself is invisible! The thing you see on screen that looks like a checkbox is actually generated by CSS. So the click event wouldn't belong to that <input> element in the first place.

To solve the problem, I moved (click)="$event.stopPropagation();" to the <div> element that wraps the custom checkbox, like so:

<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>

If I were using normal checkboxes instead of these Bootstrap 4 custom ones, either of the solutions mentioned by ConnorsFan would have worked perfectly.

like image 168
workerjoe Avatar answered Oct 01 '22 02:10

workerjoe