What is the proper ember.js-way to react to a changing checkbox

I have a checkbox like this:

{{input type="checkbox" checked=property}}

When I click the checkbox the property is changed. Now I like to call a function to persist the property. But what is the best way to do this?

  1. I could bind an observer to property, but this is consindered bad.
  2. I could bind an action to input oder click.

    {{input ... input=(action "actionName") click=(action "actionName")}}
    

    This doesn't work because the property has still the old value when the action is called.

  3. Extending the class Checkbox:

    import Checkbox from '@ember/component/checkbox';
    Checkbox.reopen({
        onChange: null,
        change() {
            this._super();
            if (this.onChange) this.onChange();
        }
    });
    ...
    {{input ... onChange=(action "actionName")}}
    

    But the function change is not documented, even though the source code indicates that it is feasable to override.

  4. I could bind an action to didUpdate or didUpdateAttrs, but the action is called twice. In my case this wouldn't be a problem, because the property is part of a model, so I could call model.get('hasDirtyAttributes') in the action. [Update] In my test case the action was called twice but in my real code it is only called once, so this seems to be the best solution?[/Update]

So what is the proper ember.js-way to do this?

Upvotes: 0

Views: 840

Answers (2)

rinold simon
rinold simon

Reputation: 3052

Have a look at my ember-twiddle example.

I would suggest using input helper,

({input type="checkbox" click=(action "setProperty") checked=my_property}}

toggle the property inside the action

setProperty() {
  // toggle the property on click
  this.toggleProperty("my_property");
  console.log(this.get('my_property')); // returns true or false based on the checked value
  .. // do whatever stuff you want
}

If your at the most recent version of ember 3.9, have a look at this

Upvotes: 0

mistahenry
mistahenry

Reputation: 8724

I personally prefer one way binding with checkboxes. I use the native input like so:

<input type="checkbox" checked={{myValue}} onclick={{action (mut myValue) value="target.checked"}}>

Check this twiddle to see it live in action. This is the easiest, non-library approach for 1-way bound checkboxes, which I would argue is the "ember-way" as of 2.x (although I do know people that still like and use the 2-way bound input which more requires observers in cases like what you described as far as I can tell).

In one of my projects, I use ember-paper which uses a nicely displayed checkbox without input and I believe the correct aria-bindings for a11y. They leverage click to invoke onChange

click() {
    if (!this.get('disabled')) {
      invokeAction(this, 'onChange', !this.get('value'));
    }
    // Prevent bubbling, if specified. If undefined, the event will bubble.
    return this.get('bubbles');
}

such that you can use with the following api

{{#paper-checkbox value=value1 onChange=(action (mut value1))}}
    A checkbox: {{value1}}
{{/paper-checkbox}}

You can see the example and how the template and component js are implemented for inspiration should you want a better looking checkbox than native

Upvotes: 3

Related Questions