Botones de radio Knockout + Bootstrap 3

Relacionado con: Bootstrap Radio Button Group

HTML:


Javascript:

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

JsFiddle:

  • Sin datos-alternar: http://jsfiddle.net/fDMM2/
  • Con data-toggle: http://jsfiddle.net/Kf3tj/1/

Tengo el código anterior que estoy tratando de poner en funcionamiento como lo espero. El problema es que cuando data-toggle="buttons" se agrega al btn-group div (como en el ejemplo de Bootstrap 3 ), el enlace knockout deja de funcionar. Si dejo la información desactivada del grupo de botones, el enlace funciona como se espera pero el grupo de botones se ve horrible. Sé que esto no funcionó en Bootstrap 2 porque en realidad no usaban la entrada de radio para su estilo de radio. ¿Cómo es que se niega a trabajar ahora aunque lo hagan?

Los botones de bootstrap y el enlace checked knockout todavía no están jugando bien:

  • knockout utiliza el evento de click dentro del enlace checked para activar el observador subyacente para cambiar
  • bootstrap se suscribe en el evento click para hacer el alternar pero llama a e.preventDefault() para que no se notifique a KO sobre el clic.

Una posible solución es crear un controlador de enlace personalizado en el que se suscriba en el evento de change (esto se inicia con bootstrap en toogle) y establezca su valor observable allí:

 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); } } } 

Y úsalo en tu vista con:

  

Demostración original con Bootstrap 3.0.2 JSFiddle .
Demostración actualizada usando Bootstrap 3.2.0 JSFiddle .

No me puedo atribuir el mérito de esto, ya que una vez en mis compañeros de trabajo se le ocurrió, pero funciona muy bien.

 

cambiar el controlador @nemesv propuesto para ser esto: y funcionó en mi aplicación muy bien.

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

Knockstrap parece ser un enlace entre Bootstrap y Knockout, y parece mantenerse bastante actualizado. Con respecto a los botones de radio en específico, utilizan este código:

 // Knockout checked binding doesn't work with Bootstrap radio-buttons ko.bindingHandlers.radio = { init: function (element, valueAccessor) { if (!ko.isObservable(valueAccessor())) { throw new Error('radio binding should be used only with observable values'); } $(element).on('change', 'input:radio', function (e) { // we need to handle change event after bootsrap will handle its event // to prevent incorrect changing of radio button styles setTimeout(function() { var radio = $(e.target), value = valueAccessor(), newValue = radio.val(); value(newValue); }, 0); }); }, update: function (element, valueAccessor) { var $radioButton = $(element).find('input[value="' + ko.unwrap(valueAccessor()) + '"]'), $radioButtonWrapper; if ($radioButton.length) { $radioButtonWrapper = $radioButton.parent(); $radioButtonWrapper.siblings().removeClass('active'); $radioButtonWrapper.addClass('active'); $radioButton.prop('checked', true); } else { $radioButtonWrapper = $(element).find('.active'); $radioButtonWrapper.removeClass('active'); $radioButtonWrapper.find('input').prop('checked', false); } } }; 

Aquí se encuentra un enfoque mucho más sencillo.

Simplemente no podemos usar el atributo de data-toggle e intentar lograr el mismo comportamiento utilizando el enlace de datos de knockout.

Es casi tan simple como las radios nativas html.

 var ViewModel = function() { this.optionsValue = ko.observable("1"); }; ko.applyBindings(new ViewModel()); 
 input[type="radio"] { /* Make native radio act the same as bootstrap's radio. */ display: none; }