twitter-bootstrap 淘汰赛 + Bootstrap 3 单选按钮

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20077475/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 19:15:47  来源:igfitidea点击:

Knockout + Bootstrap 3 Radio Buttons

javascripthtmltwitter-bootstrapknockout.jstwitter-bootstrap-3

提问by Kittoes0124

Related to: Bootstrap Radio Button Group

相关:Bootstrap 单选按钮组

HTML:

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:

Javascript:

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

ko.applyBindings(new ViewModel());

JsFiddle:

JsFiddle:



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?

我有上面的代码,我正在尝试按照我的预期工作。问题是当data-toggle="buttons"被添加到 btn-group div(如在Bootstrap 3 示例中)时,淘汰赛绑定停止工作。如果我离开按钮组的数据切换,那么绑定会按预期工作,但按钮组看起来很糟糕。我知道这在 Bootstrap 2 中不起作用,因为他们实际上并没有将收音机输入用于收音机样式。为什么它现在拒绝工作,即使他们这样做了?

回答by nemesv

The bootstrap buttonsand the knockout checkedbinding are still not playing nice:

引导按钮淘汰赛checked结合仍然没有踢得好看:

  • knockout uses the clickevent inside the checkedbinding 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.
  • 淘汰赛使用绑定click内的事件 checked来触发底层 observable 改变
  • bootstrap 订阅 click 事件以进行切换但调用,e.preventDefault()因此 KO 不会收到有关点击的通知。

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

一种可能的解决方案是创建一个自定义绑定处理程序,您可以在其中订阅change事件(这是由工具上的引导程序触发的)并在那里设置您的 observables 值:

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.2JSFiddle.
Updated demo using Bootstrap 3.2.0JSFiddle.

使用Bootstrap 3.0.2 JSFiddle 的原始演示。
使用Bootstrap 3.2.0 JSFiddle更新演示。

回答by Matthew Will

I can't take credit for this since once on my coworkers came up with it but it works really well.

我不能相信这一点,因为有一次我的同事想出了它,但它真的很好用。

<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>

回答by J3soon

There is a much easier approach found here.

有发现一个更容易的方法在这里

We can just not use the data-toggleattribute and try to achieve the same behavior using knockout's data binding.

我们可以不使用该data-toggle属性并尝试使用淘汰赛的数据绑定来实现相同的行为。

It's almost as simple as the native html radios.

它几乎和原生 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;
}
<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>

回答by danatcofo

change the handler @nemesv proposed to be this: and it worked in my app just fine.

将@nemesv 提议的处理程序更改为:它在我的应用程序中运行良好。

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

回答by CC Inc

Knockstrapappears to be a binding between Bootstrap and Knockout, and it appears to be kept pretty well up to date. Concerning radio buttons in specific, they utilize this code:

Knockstrap似乎是 Bootstrap 和 Knockout 之间的绑定,并且它似乎一直保持最新状态。关于具体的单选按钮,他们使用以下代码:

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

回答by izzy

There's a simple solution here that I'm surprised hasn't been mentioned yet.

这里有一个简单的解决方案,我很惊讶还没有提到。

1) Remove the data-toggle="buttons"from the btn-group

1)data-toggle="buttons"btn-group 中删除

Now knockout should be working

现在淘汰赛应该有效

2) Bootstrap applies custom css for these inputs to hide them, that we just lost by removing the data-toggle, so apply the following css to the radio inputs:

2) Bootstrap 为这些输入应用自定义 css 以隐藏它们,我们刚刚通过删除数据切换丢失了它们,因此将以下 css 应用于无线电输入

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

3) Last thing we need is for the selected option's button to have the active class. Add the following to the label buttons:

3)我们需要的最后一件事是使所选选项的按钮具有活动类。将以下内容添加到标签按钮

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