Я использую привязку выбора с выбиванием, где весь объект привязан как значение ... а не только строка.
bootstrap-multiselect это не понравилось, потому что он использует «значение», чтобы связать элементы своего раскрывающегося списка с соответствующей опцией выбора. Для этого вы должны установить атрибут «optionsValue» в привязке нокаута, чтобы параметр имел атрибут «значение». Однако установка атрибута optionsValue тогда дает ожидаемый результат установки только этого значения в моем selectedOptions observableArray ... а не всего объекта.
Вполне возможно, что я единственный человек, который использует функциональность knockout, которая позволяет вам привязывать параметры ко всем объектам, но на всякий случай я нет ... вот исправление взлома:
Созданы две новые опции bootstrap-multiselect, названные «optionsKey» и «observableKey», чтобы он знал, куда идти для значения, к которому оно может относиться:
<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);
}
}
},
Спасибо, включу в FAQ! Я уверен, что это полезно и для других пользователей.
Спасибо за этот совет - я также пытался выполнить привязку для выбора объектов, и эта запись была очень полезной. Единственное, что мне нужно было сделать в дополнение к коду @ APM3 , это также заполнить атрибут «значение» моих параметров в функции SetOptionKey:
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. В этом коде вам не нужно вводить параметр в виртуальную машину.
//Just like this one
myVM.SetOptionKey = function ( option, item ) {
ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};
Я добавил препроцессор в привязки, чтобы неявно добавить optionsAfterRender
.