Bootstrap切换按钮的敲除绑定

时间:2015-12-15 18:05:13

标签: twitter-bootstrap knockout.js twitter-bootstrap-3 durandal knockout-2.0

我正在寻找KnockoutJS中的一种方法,将切换按钮绑定到一个在选择特定值(按钮)时被调用的函数。

我尝试了几种解决方案并使用KnockoutJS运行它,但是当我向它添加Boostrap时,它仍然无效。

此处显示的代码不会触发与checked事件关联的处理函数。有关最新的工作示例,请使用JSFiddle。

HTML:

<div id="access-rights-control" class="btn-group pull-right" data-toggle="buttons">
  <label class="btn btn-xs">
    <input type="radio" name="status" value="1" id="status-published" data-bind="checked: $root.allowAccessHandler" />Allow access
  </label>
  <label class="btn btn-xs active">
    <input type="radio" name="status" value="0" id="status-draft" checked /> No change
  </label>
</div>

JS:

var viewModel = function() {
  this.allowAccessHandler = function() {
    alert("Works!");
  }
};
ko.applyBindings(new viewModel());

的jsfiddle: http://jsfiddle.net/p8nSe/191/

4 个答案:

答案 0 :(得分:4)

也许你想要的是类似下面的代码片段。请查看并提供反馈意见。

ko.bindingHandlers["bsChecked"]  ={
  init: function(element, valueAccessor){
    ko.utils.registerEventHandler(element,"change",function(event){
        var check = $(event.target);
        valueAccessor()(check.val());      
    });
  }
 
};

var viewModel = function() {
  
  this.checkedButton = ko.observable("2").extend({ notify: 'always' });
  
  this.checkedButton.subscribe( function(checkedVal) {
    // here you can decide what to do depends on the new checkedVal
    alert("Works! : "+ checkedVal);
  },this); 
  
};
ko.applyBindings(new viewModel());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet"/>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div id="access-rights-control" class="btn-group pull-left" data-toggle="buttons">
    <label class="btn btn-xs btn-default">
    <input type="radio" name="status" value="1" data-bind="bsChecked: checkedButton" />Allow access
  </label>
  <label class="btn btn-xs btn-default">
    <input type="radio" name="status" value="2" data-bind="bsChecked: checkedButton" />No change
  </label>
</div>

更新

  

创建了一个绑定处理程序来处理由bootstrap引起的阻止更改,因此这是一种解决方法,我建议您阅读KO custom bindings并实现绑定处理程序的update函数。 / p>

答案 1 :(得分:1)

如果你想在点击input时运行某些东西,那么你需要使用event绑定而不是checked绑定(它只是将选中的状态绑定到一个可观察的状态) ,它不是一个事件处理程序)。类似的东西:

&#13;
&#13;
var viewModel = function() {
  this.allowAccessHandler = function() {
    alert("Works!");
  }
};
ko.applyBindings(new viewModel());
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="access-rights-control" class="btn-group pull-right" data-toggle="buttons">
  <label class="btn btn-xs">
    <input type="radio" name="status" value="1" id="status-published" data-bind="event: { change: $root.allowAccessHandler }" />Allow access
  </label>
  <label class="btn btn-xs active">
    <input type="radio" name="status" value="0" id="status-draft" /> No change
  </label>
</div>
&#13;
&#13;
&#13;

现在,如果您的checked状态绑定到视图模型中的属性,那么仅subscribe到该属性可能会更好,而不是将事件处理程序附加到DOM,因为更加内联分离您的视图和视图模型。

答案 2 :(得分:1)

我认为你有两个问题:

  1. 您没有Bootstrap广播组的绑定处理程序,这意味着您的checked绑定无法正常工作
  2. 您没有正确使用checked绑定。
  3. 我可以帮你解决第二个问题。在所有元素具有相同name属性和不同value属性的无线电组中,绑定到checked可观察量的变量将获得所选无线电项的值。

    您可以订阅observable并在获得特定值时执行操作。

    &#13;
    &#13;
    var viewModel = function() {
      this.radioSelected = ko.observable();
      this.radioSelected.subscribe(function(newValue) {
        console.debug("Comparing", newValue, '1');
        if (newValue === '1') {
          alert("Works!");
        }
      });
      this.radioSelected('0');
      this.output = ko.observableArray();
    };
    ko.applyBindings(new viewModel());
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <div id="access-rights-control" class="btn-group pull-right" data-toggle="buttons">
      <label class="btn btn-xs btn-default">
        <input type="radio" name="status" value="1" data-bind="checked: radioSelected" />Allow access
      </label>
      <label class="btn btn-xs btn-default active">
        <input type="radio" name="status" value="0" data-bind="checked: radioSelected" />No change
      </label>
    </div>
    <div data-bind="foreach:output">
      <div data-bind="text:$data">
      </div>
    </div>
    &#13;
    &#13;
    &#13;

    再次,如果你有Bootstrap样式的单选按钮,这将无法工作,因为Bootstrap以Knockout未设置检测的方式摆弄DOM。所以你需要a binding handler that works with Bootstrap radio magic。这可能要求您的方法略有不同(即,您可能不会使用checked绑定)我不知道。

答案 3 :(得分:0)

最后,我找到了一种原生的方法,并完成了任务。我不确定它是否是最通用的,因为我必须覆盖ko.bindingHandlers.radio,但它有效。

ko.bindingHandlers.radio = {
      init: function(element, valueAccessor, allBindings, data, context) {
        var $buttons, $element, observable;
        observable = valueAccessor();
        if (!ko.isWriteableObservable(observable)) {
          throw "You must pass an observable or writeable computed";
        }
        $element = $(element);
        if ($element.hasClass("btn")) {
          $buttons = $element;
        } else {
          $buttons = $(".btn", $element);
        }
        elementBindings = allBindings();
        $buttons.each(function() {
          var $btn, btn, radioValue;
          btn = this;
          $btn = $(btn);
          radioValue = elementBindings.radioValue || $btn.attr("data-value") || $btn.attr("value") || $btn.text();
          $btn.on("click", function() {
            observable(ko.utils.unwrapObservable(radioValue));
          });
          return ko.computed({
            disposeWhenNodeIsRemoved: btn,
            read: function() {
              $btn.toggleClass("active", observable() === ko.utils.unwrapObservable(radioValue));
            }
          });
        });
      }
    };

    var viewModel = function() {
      this.radioSelected = ko.observable('0');
      this.radioSelected.subscribe(function(newValue) {
        console.debug("Comparing", newValue, '1');
        if (newValue === '1') {
          alert("Works!");
        }
      });
    };
    ko.applyBindings(new viewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet"/>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div class="btn-group">
  <button type="button" class="btn" data-bind="radio: radioSelected, radioValue: '1'">Allow access</button>
  <button type="button" class="btn" data-bind="radio: radioSelected, radioValue: '0'">No change</button>
</div>

JSFiddle:http://jsfiddle.net/p8nSe/192/