jquery-mobileknockout.js

Knockout and jQuery Mobile: Binding data to select lists


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.


Solution

  • 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: https://groups.google.com/forum/#!msg/knockoutjs/XXK3k7av2_Q/rbugjOo5lqAJ