J'utilise la liaison de sélection knockout où un objet entier est lié comme valeur... pas seulement une chaîne.
bootstrap-multiselect n'a pas aimé cela car il utilise la "valeur" pour relier ses éléments de liste déroulante à l'option de sélection correspondante. Pour ce faire, vous devez avoir défini l'attribut "optionsValue" dans votre liaison knockout afin que l'option ait un attribut "value". Cependant, la définition de l'attribut "optionsValue" a alors le résultat attendu de définir uniquement cette valeur dans mon selectedOptions observableArray ... pas l'objet entier.
Il est tout à fait possible que je sois la seule personne à utiliser la fonctionnalité de knockout qui vous permet de lier les options à des objets entiers, mais juste au cas où je ne le serais pas... voici le correctif :
Création de deux nouvelles options bootstrap-multiselect appelées "optionsKey" et "observableKey" afin qu'il sache où aller pour une valeur à laquelle il peut se rapporter :
<select id="mySelect" data-bind="options: myOptions, selectedOptions: mySelectedOptions, optionsText: 'myDisplayText', optionsAfterRender: SetOptionKey, multiselect: { optionsKey: 'data-key', observableKey: 'Key' }" multiple="multiple"></select>
Dans mon modèle de vue knockout, j'ai défini l'attribut référencé par "optionsKey" sur chaque option :
myVM.SetOptionKey = function ( option, item ) {
ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};
Maintenant, je plonge dans le fichier bootstrap-multiselect.js. La première chose que je devais faire ici est en haut où il ajoute le gestionnaire d'init 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 });
}
}
...
Ensuite, j'ai dû modifier la fonction createOptionValue dans bootstrap-multiselect.js pour utiliser d'abord cette clé comme valeur qu'elle définit dans ses éléments de liste :
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;
}
}
...
}
Enfin, j'ai dû modifier la fonction getOptionByValue dans bootstrap-multiselect.js pour trouver des éléments d'option basés sur cet attribut au lieu de la valeur :
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);
}
}
},
Merci, inclura ceci dans la FAQ! Je suis sûr que cela est également utile pour les autres utilisateurs.
Merci pour cette astuce - j'essayais également d'effectuer une liaison pour sélectionner des objets et cette rédaction a été très utile. La seule chose que je devais faire en plus du code de @APM3 est également de remplir l'attribut "value" de mes options dans la fonction SetOptionKey :
self.SetOptionKey = function (option, item) {
ko.applyBindingsToNode(option, { attr: { "data-key": item.Value } }, item);
ko.applyBindingsToNode(option, { attr: { "value": item.Value } }, item);
}
Merci encore pour cette rédaction.
Voir l' essentiel pour la liaison knockout cet objet pris en charge. Remplacez simplement la liaison réelle du fichier bootstrap-multiselect.js. Dans ce code, vous n'avez pas besoin de mettre dans votre machine virtuelle pour définir l'option.
//Just like this one
myVM.SetOptionKey = function ( option, item ) {
ko.applyBindingsToNode( option, { attr: { "data-key": item.Key } }, item );
};
J'ai ajouté un prétraitement aux liaisons pour ajouter implicitement optionsAfterRender
.