Knockout + Bootstrap 3 boutons de radio

Relatif à: 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:

  • Sans données basculer: http://jsfiddle.net/fDMM2/
  • Avec data-toggle: http://jsfiddle.net/Kf3tj/1/

J'ai le code ci-dessus que j'essaie de travailler comme je l'espère. Le problème est que lorsque data-toggle="buttons" est ajoutée au btn-group div (comme dans l' exemple Bootstrap 3 ), la liaison knock-out s'arrête de fonctionner. Si je laisse les données basculer du groupe de boutons, la liaison fonctionne comme prévu, mais le groupe de boutons semble terrifiant. Je sais que cela ne fonctionnait pas dans Bootstrap 2 parce qu'ils n'utilisaient pas réellement l'entrée radio pour leur style radio. Comment est-ce qu'il refuse de travailler maintenant même s'ils le font?

Les boutons bootstrap et la liaison checked knock – out ne fonctionnent toujours pas bien:

  • Knock-out utilise l'événement de click dans la liaison checked à tigger la sous-couche observable pour changer
  • Bootstrap s'abonne à l'événement de clic pour faire la balle mais appelle e.preventDefault() afin que KO ne soit pas informé du clic.

Une solution possible est de créer un gestionnaire de reliure personnalisé où vous vous abonnez sur l'événement de change (ceci est lancé par bootstrap sur Google) et configurez votre valeur observable là-bas:

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

Et utilisez-le dans votre vue avec:

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

Démo originale utilisant Bootstrap 3.0.2 JSFiddle .
Démo mise à jour utilisant Bootstrap 3.2.0 JSFiddle .

Je ne peux pas prendre de crédit pour cela car une fois sur mes collègues de travail est venu avec elle, mais cela fonctionne très bien.

 <div class="btn-group" data-toggle="buttons"> <label data-bind="css: { active: !HideInLeaderboards() }, click: function () { HideInLeaderboards(false); }, clickBubble: false" class="btn btn-default"> Show Name </label> <label data-bind="css: { active: HideInLeaderboards() }, click: function () { HideInLeaderboards(true); }, clickBubble: false" class="btn btn-default"> Hide Name </label> </div> 

Changez le gestionnaire @nemesv proposé d'être ceci: et cela a bien fonctionné dans mon application.

 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 semble être une liaison entre Bootstrap et Knockout, et il semble être bien maintenu à jour. En ce qui concerne les boutons radio spécifiques, ils utilisent ce code:

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