Bootstrap 切换按钮的敲除绑定

Posted

技术标签:

【中文标题】Bootstrap 切换按钮的敲除绑定【英文标题】:Knockout binding for Bootstrap toggle buttons 【发布时间】:2016-03-21 15:57:29 【问题描述】:

我正在寻找一种在 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/

【问题讨论】:

checked 绑定不是这样工作的 更新了问题,我这样做是因为当我添加 Bootstrap 时,KnockoutJS 的解决方案不起作用。 【参考方案1】:

也许你想要的就像下面的 sn-p 所做的那样。请查看并提供反馈。

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>

更新

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

【讨论】:

虽然它适用于 KnockoutJS,但它不适用于添加的 Bootstrap。我认为这从一开始就是我的问题。您可以查看更新的 JSFiddle。 @PeterGerhat 现在看到 sn-p,我使用绑定处理程序作为解决引导程序阻止事件的方法。所以你只需要对绑定处理程序接受的元素类型进行一些验证,一切都很好。 这看起来不错,如果你可以让它设置在ko.observable("2")中设置的初始状态,这将是解决方案【参考方案2】:

如果您希望在单击input 时运行某些东西,那么您需要使用event 绑定而不是checked 绑定(它只是将检查状态绑定到可观察的,它不是事件处理程序)。比如:

var viewModel = function() 
  this.allowAccessHandler = function() 
    alert("Works!");
  
;
ko.applyBindings(new viewModel());
<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>

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

【讨论】:

我不这么认为,KO JS 的目的之一是抽象直接的 DOM 操作。 @JoelRamosMichaliszen:我已经在底部写了一个注释。但这回答了 OP 提出的问题,并向他们展示了如何附加除click 之外的事件处理程序,他们显然对此感到困惑。【参考方案3】:

我认为你有两个问题:

    您没有 Bootstrap 单选组的绑定处理程序,这意味着您的 checked 绑定无法正常工作 您没有正确使用checked 绑定。

我可以帮你解决第二个问题。在所有元素都具有相同name 属性和不同value 属性的单选组中,绑定到checked observable 的变量将获得所选单选项的值。

您可以订阅 observable 并在它获得特定值时采取行动。

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

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

【讨论】:

您的示例适用于 KnockoutJS,但是当我向其中添加 Bootstrap 时它不会。也许你可以再看一遍,我为你更新了 JSFiddle。 @PeterGerhat 除了查看示例之外,您还应该阅读我写的内容。 当我在 KnockoutJS 下使用 Bootstrap 时,它的解决方案不起作用。在我的回答中,我提供了一个解决方法,其中定义了 radio 绑定,并且一旦定义好。【参考方案4】:

最后,我找到了一种可以在本地工作并完成任务的方法。我不确定它是否是最通用的,因为我必须覆盖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/

【讨论】:

以上是关于Bootstrap 切换按钮的敲除绑定的主要内容,如果未能解决你的问题,请参考以下文章

解决不一致的敲除检查绑定

具有“只读”和“禁用”等属性的敲除 attr 绑定

输入按键的敲除事件绑定导致奇怪的行为

Bootstrap 单选按钮组敲除绑定不起作用

使用 Jquery 加载填充 jquery ui 对话框时的敲除绑定

ASP.NET MVC 敲除绑定不起作用