1

The checked property isn't checking the UI.

HTML

<div id="dayGroup" data-bind="foreach: dowArr" class="btn-group input-group input-append" data-toggle="buttons">
    <label class="btn btn-primary">
        <input type="checkbox" data-bind="checked: isChecked, value: day" autocomplete="off"/>
        <span data-bind="text: day"></span>
        <span data-bind="text: isChecked"></span>
    </label>
</div>

JS

vm.dowArr.push({ day: 'MON', dow: 1, isChecked: ko.observable(true) });
vm.dowArr.push({ day: 'TUE', dow: 2, isChecked: ko.observable(false) });

The span display the values I expect i.e. MON true && TUE false, but the UI doesn't show Monday checked. It also doesn't update the isChecked observable when I check it manually.

robbpell
  • 13
  • 5
  • Interesting. I can [reproduce the issue](https://jsfiddle.net/jeroenheijmans/eu2ytfe4/1/). It's the `data-toggle` that's not playing nice with KnockoutJS, if I disable it [then it works "fine"](https://jsfiddle.net/jeroenheijmans/6bz3wgju/) but isn't styled right. I think you have a disguised duplicate of [this question](http://stackoverflow.com/q/20077475/419956), though I could not quickly get those answers to work well for this particular scenario, not sure why yet. – Jeroen Jun 14 '16 at 21:27

1 Answers1

1

The data-tobble="buttons" bit doesn't play nice with KnockoutJS, because Bootstrap internally will be handling the click on the label and doing a preventDefault from double-toggling the checkbox.

This other question is nearly a duplicate, though for some reason I couldn't get the custom binding handlers from the answers there (which is probably the most appropriate approach) to work for your specific scenario. This is why I'm posting a seperate answer here.

A workaround for your current situation is to just plainly get rid of the input element. Because you're working with KnockoutJS this is probably/perhaps not a big issue, because you typically post serialized view models to your back-end (and do not rely on a html form with inputs). If you do, you can just workaround by:

  1. Using a click handler (which looks cleaner than below with e.g. view model constructor functions);
  2. Setting .active initially yourself (initial state should be set by user code according to the docs);

Here's a demo:

var vm = { dowArr: ko.observableArray([]) };
vm.dowArr.push({ day: 'MON', dow: 1, isChecked: ko.observable(true) });
vm.dowArr.push({ day: 'TUE', dow: 2, isChecked: ko.observable(false) });
ko.applyBindings(vm);
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div id="dayGroup" data-bind="foreach: dowArr" class="btn-group input-group input-append" data-toggle="buttons">
    <label class="btn btn-primary" 
           data-bind="click: function() { $data.isChecked(!$data.isChecked()); },
                      css: { active: isChecked }">
        <span data-bind="text: day"></span>
        <span data-bind="text: isChecked"></span>
    </label>
</div>
<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339