Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout + Bootstrap 3 Radio Buttons

Related to: Bootstrap Radio Button Group

HTML:

<div class="btn-group" data-toggle="buttons">     <label class="btn btn-primary">         <input type="radio" name="options" id="option1" value="1" data-bind="checked: optionsValue"> Option 1     </label>     <label class="btn btn-primary">         <input type="radio" name="options" id="option2" value="2" data-bind="checked: optionsValue"> Option 2     </label>     <label class="btn btn-primary">         <input type="radio" name="options" id="option3" value="3" data-bind="checked: optionsValue"> Option 3     </label> </div> <br /> <span data-bind="text: optionsValue"></span> 

Javascript:

var ViewModel = function() {     this.optionsValue = ko.observable() };  ko.applyBindings(new ViewModel()); 

JsFiddle:

  • Without data-toggle: http://jsfiddle.net/fDMM2/
  • With data-toggle: http://jsfiddle.net/Kf3tj/1/

I have the above code which I'm trying to get working as I expect it to. The problem is that when data-toggle="buttons" is added to the btn-group div (as in the Bootstrap 3 example) the knockout binding stops working. If I leave the data-toggle off of the buttons group then the binding works as expected but the button group looks awful. I know that this didn't work in Bootstrap 2 because they didn't actually use the radio input for their radio styling. How come it refuses to work now even though they do?

like image 418
Kittoes0124 Avatar asked Nov 19 '13 16:11

Kittoes0124


1 Answers

The bootstrap buttons and the knockout checked binding are still not playing nice:

  • knockout uses the click event inside the checked binding to tigger the underlaying observable to change
  • bootstrap subscribes on the click event to do the toggling but calls e.preventDefault() so KO won't be notified about the click.

One possible solution is to create a custom binding handler where you subscribe on the change event (this is fired by bootstrap on toogle) and set your observables value there:

ko.bindingHandlers.bsChecked = {     init: function (element, valueAccessor, allBindingsAccessor,     viewModel, bindingContext) {         var value = valueAccessor();         var newValueAccessor = function () {             return {                 change: function () {                     value(element.value);                 }             }         };         ko.bindingHandlers.event.init(element, newValueAccessor,         allBindingsAccessor, viewModel, bindingContext);     },     update: function (element, valueAccessor, allBindingsAccessor,     viewModel, bindingContext) {         if ($(element).val() == ko.unwrap(valueAccessor())) {              setTimeout(function () {                 $(element).closest('.btn').button('toggle');              }, 1);          }     } } 

And use it in your view with:

<label class="btn btn-primary">     <input type="radio" name="options" id="option1" value="1"             data-bind="bsChecked: optionsValue"> Option 1 </label> 

Original demo using Bootstrap 3.0.2 JSFiddle.
Updated demo using Bootstrap 3.2.0 JSFiddle.

like image 145
nemesv Avatar answered Sep 19 '22 05:09

nemesv