it-swarm.com.de

Knockout + Bootstrap 3 Optionsfelder

Verwandt mit: Bootstrap-Optionsfeldgruppe

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:


Ich habe den obigen Code, den ich versuche, so zu arbeiten, wie ich es erwartet habe. Das Problem ist, dass, wenn data-toggle="buttons" zur btn-group div hinzugefügt wird (wie im Bootstrap 3-Beispiel ), die Knockout-Bindung nicht mehr funktioniert. Wenn ich den Datenumschalter der Schaltflächengruppe nicht zulasse, funktioniert die Bindung wie erwartet, aber die Schaltflächengruppe sieht schrecklich aus. Ich weiß, dass dies in Bootstrap 2 nicht funktioniert hat, weil sie den Radioeingang nicht für ihr Radio-Styling verwendet haben. Wieso weigert es sich jetzt zu arbeiten, obwohl sie es tun?

31
Kittoes0124

Die Bootstrap-Buttons und die Knockout checked Bindung spielen immer noch nicht Nice:

  • knockout verwendet das click -Ereignis in der checked-Bindung, um das unterlegbare Observable zu verändern
  • bootstrap abonniert das click -Ereignis, um das Umschalten durchzuführen, ruft jedoch e.preventDefault() auf, sodass KO nicht über den Klick informiert wird.

Eine mögliche Lösung besteht darin, einen benutzerdefinierten Bindungshandler zu erstellen, bei dem Sie das Ereignis change abonnieren (das von bootstrap auf Google ausgelöst wird) und Ihren Wert für observables dort festzulegen:

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

Und verwenden Sie es in Ihrer Ansicht mit:

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

Ursprüngliche Demo mit Bootstrap 3.0.2 JSFiddle .
Aktualisierte Demo mit Bootstrap 3.2.0 JSFiddle .

49
nemesv

Ich kann dies nicht anerkennen, da meine Kollegen es einmal gemacht haben, aber es funktioniert wirklich gut.

<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>
15
Matthew Will

Ändern Sie den Handler @nemesv vorgeschlagen, dies zu sein: und es hat in meiner App ganz gut funktioniert.

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

Knockstrap scheint eine Bindung zwischen Bootstrap und Knockout zu sein und scheint ziemlich gut auf dem neuesten Stand zu sein. Bei speziellen Optionsfeldern verwenden sie diesen 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);
        }
    }
};
1
CC Inc

Es gibt einen viel einfacheren Ansatz hier

Wir können das data-toggle-Attribut einfach nicht verwenden und versuchen, das gleiche Verhalten durch die Datenbindung des Knockouts zu erreichen.

Es ist fast so einfach wie die nativen HTML-Radios.

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;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="btn-group">
  <label class="btn btn-primary" data-bind="css: {active: optionsValue() == '1'}">
    <input type="radio" name="options" id="option1" value="1" data-bind="checked: optionsValue">Option 1
  </label>
  <label class="btn btn-primary" data-bind="css: {active: optionsValue() == '2'}">
    <input type="radio" name="options" id="option2" value="2" data-bind="checked: optionsValue">Option 2
  </label>
  <label class="btn btn-primary" data-bind="css: {active: optionsValue() == '3'}">
    <input type="radio" name="options" id="option3" value="3" data-bind="checked: optionsValue">Option 3
  </label>
</div>
<br/>
<span data-bind="text: optionsValue"></span>

1
J3soon

Es gibt eine einfache Lösung, von der ich überrascht bin, dass sie noch nicht erwähnt wurde.

1) Entfernen Sie den data-toggle="buttons" aus der btn-Gruppe

Jetzt sollte der Knockout funktionieren

2) Bootstrap wendet benutzerdefinierte CSS für diese Eingänge an, um sie auszublenden, die wir gerade durch das Entfernen des Datenumschalters verloren haben. Wenden Sie daher die folgenden CSS an die Radio Eingänge an:

position: absolute;
clip: rect(0,0,0,0);
pointer-events: none;

3) Das letzte, was wir brauchen, ist, dass die Schaltfläche der ausgewählten Option die aktive Klasse hat. Fügen Sie den Beschriftungsschaltflächen Folgendes hinzu:

data-bind="css: {active: optionsValue() == valueOfThisInput}"
0
izzy