1
votes

I am trying to have a checkbox inside a button and both clicking on the checkbox or the button should toggle the checkbox and the boolean value bound to it from the view model.

app.html:

<template>
  <h1>${heading}</h1>
  <button type="button" click.trigger="toggleIsChecked()">
    <input type="checkbox" checked.bind="isChecked"> ${isChecked}
  </button>
</template>

app.ts:

export class App {
  isChecked: boolean;

  toggleIsChecked() {
      this.isChecked = !this.isChecked;
  }
}

What happens is that when I click the button (outside the checkbox) everything works as expected. But when I click the checkbox the boolean value in the view model changes but the checkbox is not checked or unchecked. What could be causing this?

I have tried different approaches but they all produce similar results. While debugging I noticed the checkbox gets checked but something in the Aurelia framework removes it almost instantly. Seems like the event handling is not working properly?

EDIT: I made a gist so you can try it yourself: https://gist.run/?id=4a7b2c11db33bdb37213eb4ea1b5b2b0

3
IIRC, on the checkbox you should be using one-way binding: checked.bind="isChecked" should be checked.one-way="isChecked"; also, you probably want to use a click.delegate, not a trigger. - Metro Smurf
Also, take a look at this SO question: stackoverflow.com/questions/35296915 - Metro Smurf
Hi, thanks for the tips, but switching to one-way binding did not fix it and neither did click.delegate. I have read the SO question you linked before and tried the different suggestions there but without success. Actually the accepted answer to the question you linked suggests using two-way binding instead of one-way. - mattipet
Use a label instead. This is just bad HTML. - powerbuoy
I admit it is not pretty nor is it probably very good HTML but the reason I asked was to understand better how events work in Aurelia. Again thanks for all the comments! - mattipet

3 Answers

2
votes

Same explanation with Fabio Luz & going to do the same thing, but instead of checking event target tag name, You can use self binding behavior, like this

<template>
  <require from='./self'></require>
  <h1>${heading}</h1>
  <button type="button" click.delegate="toggleIsChecked() & self">
    <input type="checkbox" checked.bind="isChecked"> ${isChecked}
  </button>
</template>

What self binding behavior does here is to ensure toggleIsChecked only fires when you click on button itself, not its descendant, same with this block of code:

toggleIsChecked(event) {
  if (event.target === this.button) {
    // Do your thing
  }
}

Note: self just got merged, but has not been released yet. I have included the code at this gist: https://gist.run/?id=5e66dfd996d852344a524010ae82a936

You can read more about the PR here: https://github.com/aurelia/templating-resources/pull/263

3
votes

It's not the Aurelia framework that is "removing" the checking. What is happening is that when you click the checkbox, the isChecked is automatically set to true, then toggleIsChecked() is fired and isChecked is set to false (isChecked is set twice when you click the checkbox). To solve this you have to not set isChecked if the target is the checkbox. Something like this:

JS

toggleIsChecked(event) {
  if (event.target.tagName === 'INPUT') {
    return true; //checkbox has been clicked, do nothing!
  }
  this.isChecked = !this.isChecked;
}

HTML

<button type="button" click.trigger="toggleIsChecked($event)">
  <input type="checkbox" checked.bind="isChecked"> ${isChecked}
</button>
1
votes

Kind people at the Aurelia Gitter chat provided me with an answer. What is happening in my gist is that the default event handler is not being called. Reason for this is that Aurelia automatically calls the event.preventDefault() function. In order for the default event handler to be called I must return true from my own event handler. Here's a working gist proving how it works: https://gist.run/?id=3cb545572065cffd737f98788a4105a1

Thank you all for your answers. I decided to answer this myself since I got the answer from the Gitter chat, but the kudos belongs to the awesome Aurelia community and especially @CasiOo.