Bootstrap-multiselect: ربط KnockoutJS بقيمة الكائن (ليست قيمة بسيطة) ... تم تضمين إصلاح الاختراق

تم إنشاؤها على ٢ مايو ٢٠١٥  ·  3تعليقات  ·  مصدر: davidstutz/bootstrap-multiselect

أنا أستخدم ربط التحديد بالضربة القاضية حيث يكون الكائن بأكمله مرتبطًا بالقيمة ... وليس مجرد سلسلة.

لم يعجب bootstrap-multiselect هذا لأنه يستخدم "القيمة" لربط عناصر القائمة المنسدلة مرة أخرى بخيار التحديد المقابل. من أجل القيام بذلك ، يجب عليك تعيين سمة "optionsValue" في ربط الضربة القاضية بحيث يكون للخيار سمة "value". ومع ذلك ، فإن تعيين السمة "optionsValue" له النتيجة المتوقعة لتعيين تلك القيمة فقط في صفيفي المحدد الذي يمكن ملاحظته ... وليس الكائن بأكمله.

من المحتمل جدًا أن أكون الشخص الوحيد الذي يستخدم الوظيفة ضمن الضربة القاضية التي تتيح لك ربط الخيارات بكائنات بأكملها ، ولكن فقط في حال لم أكن ... إليك إصلاح الاختراق:

أنشأ خيارين جديدين للتحديد المتعدد للتمهيد يسمى "مفتاح الخيارات" و "المفتاح القابل للملاحظة" بحيث يعرف إلى أين يتجه للحصول على قيمة يمكن أن ترتبط بها:

<select id="mySelect" data-bind="options: myOptions, selectedOptions: mySelectedOptions, optionsText: 'myDisplayText', optionsAfterRender: SetOptionKey, multiselect: { optionsKey: 'data-key', observableKey: 'Key' }" multiple="multiple"></select>

في نموذج طريقة العرض بالضربة القاضية ، قمت بتعيين السمة المشار إليها بواسطة "optionsKey" في كل خيار:

myVM.SetOptionKey = function ( option, item ) {
    ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};

الآن أغوص في ملف bootstrap-multiselect.js. أول شيء يجب أن أفعله هنا هو في الجزء العلوي حيث يتم إضافة معالج التهيئة بالضربة القاضية.

init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
    ...
    if (allBindings.has('selectedOptions')) {
        var selectedOptions = allBindings.get('selectedOptions');
        if (ko.isObservable(selectedOptions)) {
            ko.computed({
                read: function () {
                    selectedOptions();

                    // Added to handle knockout binding to an object...not just a value
                    // multiselect needs the selected property on the options, else it wont show them on refresh
                    if ((config.optionsKey !== undefined) &&
                        (config.optionsKey !== null) &&
                        (config.optionsKey.length > 0) &&
                        (config.observableKey !== undefined) &&
                        (config.observableKey !== null) &&
                        (config.observableKey.length > 0)) {
                        var _optionsKey = config.optionsKey;
                        var _observableKey = config.observableKey;
                        ko.utils.arrayForEach(selectedOptions(), function (selectedOption) {
                            $("option[" + _optionsKey + "='" + selectedOption[_observableKey]() + "']", $element).prop('selected', true);
                        })
                    }

                    setTimeout(function () {
                        $element.multiselect('refresh');
                    }, 1);
                },
                disposeWhenNodeIsRemoved: element
            }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
        }
    }
    ...

بعد ذلك ، اضطررت إلى تعديل وظيفة createOptionValue في bootstrap-multiselect.js لاستخدام هذا المفتاح أولاً كقيمة يحددها في عناصر القائمة الخاصة به:

createOptionValue: function (element) {
    ...

    var value = $element.val();
    // Added to handle knockout binding to an object...not just a value
    if ((this.options.optionsKey !== undefined) && (this.options.optionsKey !== null) && (this.options.optionsKey.length > 0)) {
        var key = $element.attr(this.options.optionsKey);
        if ((key !== undefined) && (key !== null) && (key.length > 0)) {
            value = key;
        }
    }

    ...
}

أخيرًا ، اضطررت إلى تعديل وظيفة getOptionByValue في bootstrap-multiselect.js للعثور على عناصر الخيار بناءً على هذه السمة بدلاً من القيمة:

getOptionByValue: function (value) {
    var valueToCompare = value.toString();

    // Added to handle knockout binding to an object...not just a value
    if ((this.options.optionsKey !== undefined) && (this.options.optionsKey !== null) && (this.options.optionsKey.length > 0)) {
        var opt = $("option[" + this.options.optionsKey + "='" + valueToCompare + "']", this.$select).first();
        if( (opt !== undefined) && (opt !== null) ) {
            return $(opt);
        }
    }

    var options = $('option', this.$select);

    for (var i = 0; i < options.length; i = i + 1) {
        var option = options[i];
        if (option.value === valueToCompare) {
            return $(option);
        }
    }
},
question

ال 3 كومينتر

شكرًا ، سيتم تضمين هذا في التعليمات! أنا متأكد من أن هذا مفيد للمستخدمين الآخرين أيضًا.

شكرًا لك على هذه النصيحة - كنت أحاول إنجاز الربط لتحديد الكائنات أيضًا وكانت هذه الكتابة مفيدة جدًا. الشيء الوحيد الذي كان عليّ القيام به بالإضافة إلى رمز @ APM3 هو أيضًا ملء سمة "القيمة"

self.SetOptionKey = function (option, item) { ko.applyBindingsToNode(option, { attr: { "data-key": item.Value } }, item); ko.applyBindingsToNode(option, { attr: { "value": item.Value } }, item); }

شكرا مرة أخرى على هذه الكتابة.

انظر جوهر الربط بالضربة القاضية هذا الكائن المدعوم. ما عليك سوى استبدال الرابط الفعلي من ملف bootstrap-multiselect.js. في هذا الكود ، لا تحتاج إلى وضعه في جهاز vm الخاص بك لتعيين الخيار.

//Just like this one
myVM.SetOptionKey = function ( option, item ) {
    ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};

لقد أضفت المعالجة المسبقة إلى الارتباطات لإضافة optionsAfterRender ضمنيًا.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات