JQuery Chosen не обновляет опции выбора при работе с нокаутом js

Я пытаюсь сделать jQuery Chosen и KnockoutJS работать одновременно.

Проблема заключается в том, что "jQuery Chosen" отказывается обновлять список опций, даже несмотря на то, что я создал для него настраиваемую привязку.

Вот пример - http://jsfiddle.net/5fGAf/

У меня есть два сменных варианта - "Страна" и "Метод" . Список вариантов "Метод" зависит от выбранной страны. Когда я выбираю страну в первый раз - все работает отлично. Но когда я хочу изменить страну - список опций "Метод" остается тем же, даже если обновленное соответствующее значение для нокаута обновляется.

Если я вручную запускаю $(".chosen-select").trigger('chosen:updated') в консоли браузера - обновляет список опций.

Пользовательский код привязки:

ko.bindingHandlers.chosen = {
  init: function(element) {             
    $(element).chosen({disable_search_threshold: 10});
  },
  update: function(element) {
    $(".chosen-select").trigger('chosen:updated');
  }
};

Ответ 1

У вас есть две проблемы:

  • в вашей скрипте нет .chosen-select, поэтому ваша функция update не найдет select, но в любом случае вы должны использовать $(element) для доступа к связанному в данный момент элементу
  • в привязки KO 3.0 запускаются независимо. Поскольку привязка chosen не связана с вашим наблюдаемым массивом, ваш update не будет срабатывать при изменении этого массива.

Вы можете решить эту проблему "обновления", явно указав зависимость от привязки options в своей настраиваемой привязке, но лучшим решением было бы делегировать ей:

ko.bindingHandlers.chosen = {
    init: function(element)  {
        ko.bindingHandlers.options.init(element);
        $(element).chosen({disable_search_threshold: 10});
    },
    update: function(element, valueAccessor, allBindings) {
        ko.bindingHandlers.options.update(element, valueAccessor, allBindings);
        $(element).trigger('chosen:updated');
    }
};

И используйте его, где вы обычно используете привязку options:

<select id="option1" class="form-control" 
    data-bind="chosen: payoutOptions, 
               optionsText: 'optionText', 
               optionsValue: 'optionValue', 
               value: activePayoutOption"></select>

Демо JSFiddle.

Ответ 2

Мое решение таково:

ko.bindingHandlers.chosen =
{
    init: function (element, valueAccessor, allBindings) {
        $(element).chosen(valueAccessor());

        // trigger chosen:updated event when the bound value or options changes

        $.each('value|selectedOptions|options'.split("|"), function (i, e) {
            var bv = allBindings.get(e);
            if (ko.isObservable(bv))
                bv.subscribe(function () { $(element).trigger('chosen:updated'); });
        });
    },
    update: function (element) {
        $(element).trigger('chosen:updated');
    }
};

Вы бы использовали его так:

<select data-bind="
    options: payoutOptions, 
    optionsText: 'optionText', 
    optionsValue: 'optionValue',
    value: activePayoutOption,
    chosen: { disable_search_threshold: 10, width:'100%' }">
</select>

Обратите внимание, что

  • Выбранная привязка - опция добавлена ​​... вместо того, чтобы изменять способ работы с данными.
  • Выбранные опции ({ width:'100%',... }) не связаны в обработчике

Ответ 3

Я использовал метод, который также совместим со всеми моими существующими привязками, поэтому мне не нужно было идти за тонну html файлов, удаляя привязку options.

ko.bindingHandlers.chosen = {
    init: function(element, valueAccessor, allBindings) {
        $(element).chosen({ disable_search_threshold: 10});
        var valueObservable = allBindings.get('value');
        var optionsObservable = allBindings.get('options');

        var updateList = function() {
            $(element).trigger('chosen:updated');
        }

        if (valueObservable && typeof(valueObservable.subscribe) == 'function') {
            valueObservable.subscribe(updateList);
        }

        if (optionsObservable && typeof(optionsObservable.subscribe) == 'function') {
            optionsObservable.subscribe(updateList);
        }

        $(element).chosen({ disable_search_threshold: 7, width:'100%' });
    }
};