Estoy usando el enlace de selección knockout donde un objeto completo está vinculado como valor ... no solo una cadena.
A bootstrap-multiselect no le gustó esto porque usa el "valor" para relacionar los elementos de su lista desplegable con la opción de selección correspondiente. Para que pueda hacer esto, debe haber establecido el atributo "optionsValue" en su enlace de eliminación para que la opción tenga un atributo "value". Sin embargo, establecer el atributo "optionsValue" tiene el resultado esperado de establecer solo ese valor en mi selectedOptions observableArray ... no todo el objeto.
Es muy posible que yo sea la única persona que usa la funcionalidad dentro del knockout que le permite vincular las opciones a objetos completos, pero en caso de que no lo sea ... aquí está la solución del truco:
Creó dos nuevas opciones de bootstrap-multiselect llamadas "optionsKey" y "observableKey" para que sepa a dónde ir para obtener un valor con el que pueda relacionarse:
<select id="mySelect" data-bind="options: myOptions, selectedOptions: mySelectedOptions, optionsText: 'myDisplayText', optionsAfterRender: SetOptionKey, multiselect: { optionsKey: 'data-key', observableKey: 'Key' }" multiple="multiple"></select>
En mi modelo de vista eliminatoria, configuro el atributo al que hace referencia "optionsKey" en cada opción:
myVM.SetOptionKey = function ( option, item ) {
ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};
Ahora me sumerjo en el archivo bootstrap-multiselect.js. Lo primero que tuve que hacer aquí es en la parte superior donde está agregando el controlador de inicio knockout.
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 });
}
}
...
Luego tuve que modificar la función createOptionValue en bootstrap-multiselect.js para usar primero esta clave como el valor que establece en sus elementos de lista:
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;
}
}
...
}
Por último, tuve que modificar la función getOptionByValue en bootstrap-multiselect.js para encontrar elementos de opción basados en este atributo en lugar de valor:
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);
}
}
},
¡Gracias, incluiremos esto en las preguntas frecuentes! Estoy seguro de que esto también es útil para otros usuarios.
Gracias por este consejo: también estaba tratando de lograr la vinculación para seleccionar objetos y esta redacción fue muy útil. Lo único que tuve que hacer además del código de @ APM3 es también completar el atributo "valor" de mis opciones en la función SetOptionKey:
self.SetOptionKey = function (option, item) {
ko.applyBindingsToNode(option, { attr: { "data-key": item.Value } }, item);
ko.applyBindingsToNode(option, { attr: { "value": item.Value } }, item);
}
Gracias de nuevo por este artículo.
Consulte la esencia para obtener información sobre la unión de nocaut de ese objeto admitido. Simplemente reemplace el enlace real del archivo bootstrap-multiselect.js. En este código, no es necesario que lo pongas en tu vm para configurar la opción.
//Just like this one
myVM.SetOptionKey = function ( option, item ) {
ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};
Agregué un optionsAfterRender
.