Knockout и jQuery Mobile: привязка данных к спискам - PullRequest
9 голосов
/ 21 февраля 2012

Я использую и 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 ]

14 голосов
/ 21 февраля 2012

Я решил сам. Я написал свою собственную привязку 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.

4 голосов
/ 15 июня 2012

Для моего личного опыта (с jquerymobile 1.1.0 и knockoutjs 2.1.0) я использовал только привязку jqmoptions (как видно в первом посте), чтобы иметь действительную привязку нокаута для выбора. , Чтобы привязка 'value' работала с select, просто объявите его первым в привязке

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

Похоже, что заказ обязателен: http://goo.gl/nVbHc

1 голос
/ 30 апреля 2015

Просто для ясности, лучшее решение сейчас для 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>
0 голосов
/ 24 февраля 2016

с использованием обоих 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 -> 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) {}
    }
};
...