Knockout和jQuery Mobile:将数据绑定到选择列表

时间:2012-02-21 07:56:28

标签: jquery-mobile knockout.js

我在同一个项目中同时使用Knockout(版本2.0)和jQuery Mobile(版本1.0.1)。问题在于将数据绑定到选择列表。 jQuery Mobile以一种看似选择的值和实际列表是单独元素的方式呈现选择列表。这是通过执行

来解决的
$(element).selectmenu('refresh', true);
更改列表或选定值后

。根据我的经验,这是一个危险的情况,因为开发人员经常忘记刷新选择列表。

为了简化这一点,我编写了自己的Knockout绑定处理程序。这些值使用以下代码绑定到选择列表:

<select name="selection" data-bind="jqmOptions: values, optionsValue: 'id', optionsText: 'name', value: selectedValue">
</select>

jqmOptions的实现:

ko.bindingHandlers.jqmOptions = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        if (typeof ko.bindingHandlers.options.init !== 'undefined') {
            ko.bindingHandlers.options.init(element, valueAccessor, allBindingsAccessor, viewModel);
        }
    },

    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        if (typeof ko.bindingHandlers.options.update !== 'undefined') {
            ko.bindingHandlers.options.update(element, valueAccessor, allBindingsAccessor, viewModel);
        }

        var instance = $.data(element, 'selectmenu');
        if (instance) {
            $(element).selectmenu('refresh', true);
        }
    }
};

这使用本机options绑定,但除此之外,它会在更改列表值后自动刷新选择列表。但是当我更改所选值时,这有问题。如果我首先设置列表值,我的jqmOptions将刷新选择列表,但此时,尚未设置所选值。我最终得到一个选择列表,它具有所有正确的值,并在内部选择了正确的选项,但jQuery Mobile仍然显示默认值为选中。

this.values(someArrayOfValues);
this.selectedValue(oneOfTheArrayValues);

Knockout不允许我先设置所选值然后设置列表值,因为在这种情况下,当我设置所选值时没有允许的值。因此,所选值始终未定义。

有没有办法编写一个Knockout自定义绑定,在两种情况下都会刷新选择列表元素:更改列表值和更改选定值时?

目前我使用以下代码解决了这种情况:

this.values(someArrayOfValues);
this.selectedValue(oneOfTheArrayValues);
this.values(someArrayOfValues);

然而,这不是一个非常优雅的解决方案,我想更好地解决它。

4 个答案:

答案 0 :(得分:14)

我最终解决了自己。我写了自己的jqmValue绑定:

ko.bindingHandlers.jqmValue = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        if (typeof ko.bindingHandlers.value.init !== 'undefined') {
            ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
        }
    },

    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        if (typeof ko.bindingHandlers.value.update !== 'undefined') {
            ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel);
        }

        var instance = $.data(element, 'selectmenu');
        if (instance) {
            $(element).selectmenu('refresh', true);
        }
    }
};

然后将选择列表代码更改为以下内容:

我在问这个问题之前已经尝试过这个问题了,但显然我写得很差,因为它不起作用。然而,现在有了一双新鲜的眼睛,我设法正确实现它,所以希望这个答案也解决了其他Knockout和jQuery Mobile用户的问题。

答案 1 :(得分:4)

根据我的个人经验(使用jquerymobile 1.1.0和knockoutjs 2.1.0),我只使用 jqmoptions (如第一篇文章中所见)绑定,以便有效地敲除绑定到a选择。要使'value'绑定与select配合使用,只需在绑定中将其声明为

<select name="myname" id="myid" data-bind="value: myvalue, jqmoptions: myvalues, optionsValue: 'id', optionsText: 'desc'"></select>

查看订单是强制性的:http://goo.gl/nVbHc

答案 2 :(得分:1)

为了清楚起见,现在KO 3.x的最佳解决方案是:

ko.bindingHandlers.jqmValue = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
      if (typeof ko.bindingHandlers.value.init !== 'undefined') {
        ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
      }
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
      var instance;
      if (typeof ko.bindingHandlers.value.update !== 'undefined') {
        ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel);
      }
      instance = $.data(element, 'mobile-selectmenu');
      if (instance) {
        $(element).selectmenu('refresh', true);
      }
    }
  };

匹配的HTML使用:

<select data-bind="options: optionsList, optionsValue: 'Id', optionsText: 'Title', jqmValue: knockoutobservable"></select>

答案 3 :(得分:0)

同时使用Knockout 3.3 + jQuery Mobile 1.4.5也有同样的问题 当我有多个选择绑定一个值

<select id="myselect1" data-bind="options: modelsA-Z, value: myModel"></select>
<select id="myselect2" data-bind="options: modelsFamous, value: myModel"></select>

第1 /第2选择未显示初始值,第2次未更新后...... 我最后使用下面的绑定:(替换上面的值:myModel - &gt; jqmValue:myModel)

ko.bindingHandlers.jqmValue = {
    init: function (element, valueAccessor) {
        var result = ko.bindingHandlers.value.init.apply(this, arguments);
        try {
            $(element).selectmenu("refresh");
        } catch (x) {}
        return result;
    },
    update: function (element, valueAccessor) {
        ko.bindingHandlers.value.update.apply(this, arguments);
        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        try {
            $(element).selectmenu("refresh");
        } catch (x) {}
    }
};