KnockoutJS не вызывает функцию обновления в пользовательском обработчике привязки

Я написал плагин jQuery для множественного выбора, который можно применить к обычному элементу выбора HTML.

Однако этот плагин будет анализировать элемент select и его параметры, а затем удалит элемент select из DOM и вместо этого вставит комбинацию div и флажков.

Я создал собственный обработчик привязки в Knockout следующим образом:

ko.bindingHandlers.dropdownlist = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here

    // Retrieve the value accessor
    var value = valueAccessor();
    // Get the true value of the property
    var unwrappedValue = ko.utils.unwrapObservable(value);

    // Check if we have specified the value type of the DropDownList items. Defaults to "int"
    var ddlValueType = allBindingsAccessor().dropDownListValueType ? allBindingsAccessor().dropDownListValueType : 'int';

    // Check if we have specified the INIMultiSelect options otherwise we will use our defaults.
    var elementOptions = allBindingsAccessor().iniMultiSelectOptions ? allBindingsAccessor().iniMultiSelectOptions :
        {
            multiple: false,
            onItemSelectedChanged: function (control, item) {
                var val = item.value;

                if (ddlValueType === "int") {
                    value(parseInt(val));
                }
                else if (ddlValueType == "float") {
                    value(parseFloat(val));
                } else {
                    value(val);
                }
            }
        };

    // Retrieve the attr: {} binding
    var attribs = allBindingsAccessor().attr;

    // Check if we specified the attr binding
    if (attribs != null && attribs != undefined) {

        // Check if we specified the attr ID binding
        if (attribs.hasOwnProperty('id')) {
            var id = attribs.id;

            $(element).attr('id', id);
        }

        if (bindingContext.hasOwnProperty('$index')) {
            var idx = bindingContext.$index();

            $(element).attr('name', 'ddl' + idx);
        }
    }

    if ($(element).attr('id') == undefined || $(element).attr('id') == '') {
        var id = "ko_ddl_id_" + (ko.bindingHandlers['dropdownlist'].currentIndex);

        $(element).attr('id', id);
    }

    if ($(element).attr('name') == undefined || $(element).attr('name') == '') {
        var name = "ko_ddl_name_" + (ko.bindingHandlers['dropdownlist'].currentIndex);

        $(element).attr('name', name);
    }

    var options = $('option', element);

    $.each(options, function (index) {
        if ($(this).val() == unwrappedValue) {

            $(this).attr('selected', 'selected');
        }
    });

    if (!$(element).hasClass('INIMultiSelect')) {
        $(element).addClass('INIMultiSelect');
    }

    $(element).iniMultiSelect(elementOptions);

    ko.bindingHandlers['dropdownlist'].currentIndex++;
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    var unwrappedValue = ko.utils.unwrapObservable(valueAccessor());

    var id = $(element).attr('id').replace(/\[/gm, '\\[').replace(/\]/gm, '\\]');

    var iniMultiSelect = $('#' + id);

    if (iniMultiSelect != null) {
        iniMultiSelect.SetValue(unwrappedValue, true);
    }
}};
ko.bindingHandlers.dropdownlist.currentIndex = 0;

Это преобразует исходный элемент HTML select в мой пользовательский мультиселект.

Тем не менее, когда функция обновления вызывается в первый раз, после инициализации, переменная "element" все равно будет исходным элементом select, а не моим div-оберткой, которая содержит мой пользовательский html.

И после того, как страница полностью загружена, и я изменяю значение наблюдаемой, к которой привязываюсь, функция обновления вообще не запускается!

Почему-то у меня такое чувство, что нокаут больше не "знает", что делать, потому что оригинальный элемент DOM, к которому я привязан, пропал...

Любые идеи, в чем может быть проблема здесь?

2 ответа

Решение

В Knockout есть код очистки, который будет избавляться от вычисляемых наблюдаемых, которые используются для запуска привязок, когда он определяет, что элемент больше не является частью документа.

Вы могли бы потенциально найти способ просто скрыть оригинальный элемент или поместить привязку на контейнер оригинального select (вероятно, будет хорошим вариантом), или повторно примените привязку к одному из новых элементов.

Я столкнулся с подобной проблемой сегодня, и вот как я решил ее. В моем обработчике обновлений я добавил следующую строку:

$(element).attr("dummy-attribute", ko.unwrap(valueAccessor()));

Этого достаточно для предотвращения удаления обработчика сборщиком мусора Knockout.

JSFiddle (не работает): http://jsfiddle.net/padfv0u9/

JSFiddle (исправлено): http://jsfiddle.net/padfv0u9/2/

Другие вопросы по тегам