Tom Nolan
Tom Nolan

Reputation: 1957

Checkbox will not stay checked with the data-bind in Knockout

I have a checkbox that I want to execute a function when it is clicked. The issue is, it needs to execute a different function based on whether or not the checkbox is checked. So, I setup a status observable that is set to false by default:

self.status = ko.observable(false);

I binded a function to the checkbox on click:

<input type="checkbox" data-bind="click: modify, checked: status">

And I created the function to execute a different function based on whether or not the status observable is true or false:

self.modify = function() {
    if (self.status() == false) {
        // Some other code
        alert('Now True!')
        self.status(true);
    }
    else if (self.status() == true) {
        // Some other code
        alert('Now False!');
        self.status(false)
    }
}

This function works perfectly fine. It alerts the correct message based on whether or not status is true or false, however the issue is, I cannot seem to get the checkbox to stay checked when the status is true.

http://jsfiddle.net/tsnolan23/s441hggL/

Any ideas on why the checkbox is not staying checked?

Upvotes: 3

Views: 3328

Answers (2)

Roy J
Roy J

Reputation: 43899

You don't need two bindings. The status will change when you check the box. All you need is a subscription to the observable to notice that. (The writable computed solution is about the same, but a bit more complicated than necessary.)

var Vm = function() {
  var self = this;
  self.isActive = ko.observable(false);
  self.isActive.subscribe(function (newValue) {
    if (newValue) alert("Checked");
    else alert("Unchecked");
  });
};

ko.applyBindings(new Vm());
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<label>
  <input type="checkbox" data-bind="checked: isActive" /> Check me!
</label>

Upvotes: 0

Jeroen
Jeroen

Reputation: 63870

Here's what's happening:

  1. You click the checkbox.
  2. The click handler fires, it sets status.
  3. The checked handler fires, it changes the checkbox status.
  4. The event bubbles to the browser, which reverts the change.
  5. Knockout notices this, and updates status again.

Here's a whole different approach, using writeable computeds for this purpose:

var Vm = function() {
  var self = this;
  var _isActive = ko.observable(false);
  self.isActive = ko.computed({
    read: _isActive,
    write: function(newValue) {
      _isActive(newValue);
      if (!!newValue) { alert("Something..."); }
      else { alert("Another thing."); }
    }
  });
};

ko.applyBindings(new Vm());
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<label>
  <input type="checkbox" data-bind="checked: isActive" /> Check me!
</label>

If you must for some reason use the click binding, then you should do two things:

  • return true from your handler
  • set clickBubble: false on the bindings

For example:

var Vm = function() {
  var self = this;
  
  self.isActive = ko.observable(false);
  
  self.modify = function() {
    if (self.isActive() == false) {
      // Some other code
      alert('Now True!')
    }
    else if (self.isActive() == true) {
      // Some other code
      alert('Now False!');
    }
    
    return true;
  }
};

ko.applyBindings(new Vm());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<label>
  <input type="checkbox" data-bind="click: modify, clickBubble: false, checked: isActive" /> Check me!
</label>
<pre data-bind="text: ko.toJSON($root)"></pre>

Upvotes: 4

Related Questions