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

发布于 2025-01-07 17:38:54 字数 1859 浏览 1 评论 0原文

我在同一个项目中同时使用 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);

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

I'm using both Knockout (version 2.0) and jQuery Mobile (version 1.0.1) in the same project. The problem is with binding data to select lists. jQuery Mobile presents select lists in a way where the seemingly selected value and the actual list are separate elements. This is fixed by executing

$(element).selectmenu('refresh', true);

after changing either the list or the selected value. Based on my experience, this is a dangerous situation as developers often forget to refresh select list.

To ease this, I wrote my own Knockout binding handler. The values are bound to the select list with following code:

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

The implementation of 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);
        }
    }
};

This uses the native options binding but in addition to that, it automatically refreshes select lists after changing the list values. There is a problem with this however when I'm changing the selected value. If I first set the list values, my jqmOptions refreshes the select list but at that point, the selected value is not yet set. I end up with a select list, which has all the correct values and internally the right option is selected, but jQuery Mobile still displays the default value as selected.

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

Knockout doesn't allow me to first set the selected value and then setting the list values, because in this case there are no allowed values when I'm setting the selected value. Thus the selected value is always undefined.

Is there a way to write a Knockout custom binding which would refresh the select list element in both cases: when changing the list value and when changing the selected value?

Currently I solve this situation with following code:

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

This is not very elegant solution however and I would like to solve it better.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蓝天 2025-01-14 17:38:54

我最终解决了自己。我编写了自己的 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 用户的问题。

I ended up solving myself. I wrote my own jqmValue binding:

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

The select list code is then changed to following:

I already tried implementing this yesterday before asking the question, but apparently I wrote it poorly then because it didn't work. However, now with a fresh pair of eyes I managed to implement it correctly so hopefully this answer solves the problem for other Knockout and jQuery Mobile users too.

小巷里的女流氓 2025-01-14 17:38:54

就我个人的经验(使用 jquerymobile 1.1.0 和 knockoutjs 2.1.0)而言,我仅使用 jqmoptions (如第一篇文章中所示)绑定来将有效的淘汰赛绑定到选择。要使“值”绑定与 select 一起使用,只需在绑定中将其声明为第一个即可。

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

看起来顺序是强制性的:http://goo.gl/nVbHc

For my personal experience (with jquerymobile 1.1.0 and knockoutjs 2.1.0), I've only used jqmoptions (as seen in the first post) binding to have a valid knockout binding to a select. To make 'value' binding works with select, simply declare it as first in the binding

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

Looks that the order is mandatory: http://goo.gl/nVbHc

鸠书 2025-01-14 17:38:54

为了清楚起见,现在 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>

Just for clarity, the best solution now for KO 3.x would be:

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

And the matching HTML use:

<select data-bind="options: optionsList, optionsValue: 'Id', optionsText: 'Title', jqmValue: knockoutobservable"></select>
木森分化 2025-01-14 17:38:54

同时使用 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>

第一个/第二个选择未显示初始值,第二个选择后未更新...
我最终使用下面的绑定:(替换上面的 value:myModel -> 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) {}
    }
};

using both Knockout 3.3 + jQuery Mobile 1.4.5 and also had the same problem
when i had multiple selections which binding one value

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

1st/2nd select not shown the init value and 2nd not updated after...
I finally use below binding: (replace above value:myModel -> 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) {}
    }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文