Knockout 3+ 如何将 jquery 移动单选按钮绑定到 Knockout?

Knockout 3+ How do you bind a jquery mobile radio button to knockout?

https://jsfiddle.net/9L8r9etf/2/

我一直在尝试几种不同的方法,但这是我得到的最接近的方法。由于某种原因 this.checked 始终为真。

javascript:

ko.bindingHandlers.jqmChecked = {
    init: function (element, valueAccessor) {
        ko.utils.unwrapObservable(valueAccessor()); // This hack for knockout v3
        // set the dom element to a checkbox and initialize it (for jquerymobile)
        var checkbox = $(element);
        // let jquerymobile enhance the element
        checkbox.removeAttr('data-role');
        // make it so
        checkbox.checkboxradio();
        //register change event to update the model on changes to the dom
        checkbox.on('change', function (e) {
                if(this.checked)
            valueAccessor()(this.value);
        });
    },
    update: function (element, valueAccessor) {
        // update the checked binding, important for correct radio button behaviour.
        //ko.bindingHandlers.checked.update(element, valueAccessor);
        //ko.utils.unwrapObservable(valueAccessor()); // This hack for knockout v3

        // and refresh the element (for jquerymobile)
        var checkbox = $(element);
        checkbox.checkboxradio('refresh');
        checkbox.prop("checked", valueAccessor()()).checkboxradio("refresh");

    }
};

var ViewModel = function(repeat) {
        var self = this;
        self.testa = ko.observable(true);
    self.test = ko.observable("dyn");
    if(repeat){
    self.subView = ko.observable(new ViewModel(false));
    }
};

ko.applyBindings(new ViewModel(true));

html:

<fieldset data-role="controlgroup" data-mini="true" data-type="horizontal">
  <label><input type="radio" value="inp" name="inpdynout2" checked data-bind="jqmChecked:test"/> inp</label>
  <label><input type="radio" value="dyn" name="inpdynout2" data-bind="jqmChecked:test" /> dyn</label>
  <label><input type="radio" value="out" name="inpdynout2" data-bind="jqmChecked:test" /> out</label>
</fieldset>
<hr/>
x <span data-bind="text:test"></span><br/>

我知道在淘汰赛 3 中,您需要创建自己的事件侦听器而不是使用 checked.update,但我一直无法弄清楚如何将其与原始检查绑定一起使用。

我希望绑定尽可能像 Knockout 3 香草绑定一样工作,因为我们已经被自定义绑定不完整的错误所困扰。

ko.bindingHandlers.jqmCheckedRadio = {
    init: function (element, valueAccessor) {
        // set the dom element to a checkbox and initialize it (for jquerymobile)
        var checkbox = $(element);
        // let jquerymobile enhance the element
        checkbox.removeAttr('data-role');
        // make it so
        checkbox.checkboxradio();

        checkbox.on('change', function (e) {
            if ($(this).prop( "checked")) {//this is returning true always.
                valueAccessor()(this.value);
            }
        });
    },
    update: function (element, valueAccessor) {
        // update the checked binding, i.e., check or uncheck the checkbox
        var unwrapped = ko.utils.unwrapObservable(valueAccessor()); 
        // and refresh the element (for jquerymobile)
        $(element).prop("checked", element.value === unwrapped).checkboxradio("refresh");
    }
};

这在将多个单选按钮绑定到单个可观察对象的淘汰赛 3 语义之后起作用,但使用它们的属性值而不是 checkValue。

尚未针对复选框或布尔单选按钮进行测试。

如果您需要动态数量的单选按钮,它也应该可以正常工作。

如果您能分享一些有关您在问题中提到的错误的详细信息,那就太好了。无论如何,为了保持检查的 attr 同步,我会使用这样的东西:

ko.bindingHandlers.jqmRadio = {
  init: function(element, valueAccessor, allBindings) {
    var value = valueAccessor(),
      valueUnwrapped = ko.unwrap(value);
    if (!valueUnwrapped) {
      var checkedValue = $('input[name=' + element.name + ']:checked').val();
      value(checkedValue);
    }
    return ko.bindingHandlers.checked.init.apply(this, arguments);
  },
  update: function(element, valueAccessor, allBindings) {
    var valueUnwrapped = ko.unwrap(valueAccessor()); // for dependency
    if (!!$.data(element, "mobile-checkboxradio")) {
      (element.value !== valueUnwrapped) ? $(element).removeAttr("checked"): $(element).attr("checked", "checked");
      $(element).checkboxradio("refresh");
    }
  }
};

var ViewModel = function() {
  var self = this;
  self.test = ko.observable(); // initialized by attr
  self.test2 = ko.observable("dyn"); // initialized by ko
};

$(document).ready(function() {
  ko.options.deferUpdates = true;
  ko.applyBindings(new ViewModel());
});
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
</head>

<body>
  <div data-role="page">
    <div role="main" class="ui-content">
      <fieldset data-role="controlgroup" data-mini="true" data-type="horizontal">
        <label>
          <input type="radio" name="inpdynout" checked data-bind="checkedValue:'inp', jqmRadio:test"> inp</label>
        <label>
          <input type="radio" name="inpdynout" data-bind="checkedValue:'dyn', jqmRadio:test"> dyn</label>
        <label>
          <input type="radio" name="inpdynout" data-bind="checkedValue:'out', jqmRadio:test"> out</label>
      </fieldset>
      <hr/>
      <br/>
      <fieldset data-role="controlgroup" data-mini="true" data-type="horizontal">
        <label>
          <input type="radio" name="inpdynout2" data-bind="checkedValue:'inp', jqmRadio:test2"> inp</label>
        <label>
          <input type="radio" name="inpdynout2" data-bind="checkedValue:'dyn', jqmRadio:test2"> dyn</label>
        <label>
          <input type="radio" name="inpdynout2" data-bind="checkedValue:'out', jqmRadio:test2"> out</label>
      </fieldset>
      <hr/>
      <pre data-bind="text:ko.toJSON($data)"></pre>
    </div>

  </div>
</body>

</html>