2

通常の HTML 選択要素に適用できる複数選択 jQuery プラグインを作成しました。

ただし、このプラグインは 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 選択要素がカスタムの複数選択に変換されます。

ただし、更新関数が最初に呼び出されたとき、初期化の後、「要素」変数は元の選択要素のままであり、カスタム html を一緒に保持するラッパー div ではありません。

そして、ページが完全にロードされ、バインドしているオブザーバブルの値を変更した後、更新機能はまったくトリガーされません!

どういうわけか、バインドしている元のDOM要素がなくなったため、ノックアウトが何をすべきかを「認識」していないような気がします...

ここで問題になる可能性のあるアイデアはありますか?

4

2 に答える 2

0

Knockout には、要素がドキュメントの一部ではなくなったと判断したときにバインドをトリガーするために使用される計算されたオブザーバブルを破棄するクリーンアップ コードがあります。

元の要素を非表示にする方法、または元の要素のコンテナーにバインディングを配置する方法select(おそらく適切なオプション) を見つける方法、または新しい要素の 1 つにバインディングを再適用する方法を見つけることができます。

于 2012-10-25T13:50:32.180 に答える