So I have a a number of select2 dropdowns bound using Knockout. And initially it seemed to work fine. When a user makes selections(multi select). The model is updated and life is good. My problem comes in when you have values from the model that you want to displayed as selected by default. For example when editing something. You load the form with pre-populated values.
Here is my binding handler
ko.bindingHandlers.select2 = {
init: function (el, valueAccessor, allBindingsAccessor) {
ko.utils.domNodeDisposal.addDisposeCallback(el,
function () {
$(el).select2('destroy');
});
var allBindings = allBindingsAccessor(),
select2 = ko.utils.unwrapObservable(allBindings.select2);
$(el).select2(select2);
},
update: function (el, valueAccessor, allBindingsAccessor) {
var allBindings = allBindingsAccessor();
if ("value" in allBindings) {
if ((allBindings.select2.multiple || el.multiple) && allBindings.value().constructor !== Array) {
$(el).val(allBindings.value().split(',')).trigger('change');
} else {
$(el).val(allBindings.value()).trigger('change');
}
} else if ("selectedOptions" in allBindings) {
var converted = [];
var textAccessor = function (value) { return value; };
if ("optionsText" in allBindings) {
textAccessor = function (value) {
var valueAccessor = function (item) { return item; }
if ("optionsValue" in allBindings) {
valueAccessor = function (item) { return item[allBindings.optionsValue]; }
}
var items = $.grep(allBindings.options(), function (e) { return valueAccessor(e) === value });
if (items.length === 0 || items.length > 1) {
return "UNKNOWN";
}
return items[0][allBindings.optionsText];
}
}
$.each(allBindings.selectedOptions(),
function (key, value) {
converted.push({ id: value, text: textAccessor(value) });
});
$(el).select2("data", converted);
}
$(el).trigger("change");
}
};
The selectedoptions is bound to a list of Guids. Which is a list of strings on the javascript side. As I believe the Select2 select requires strings to be able to set the selected values.
My select looks ike follows:
<select class="form-control input-sm multi-select" data-bind="selectedOptions: BrandIds, options: Brands, valueAllowUnset: true, optionsText:'Description', optionsValue: 'Value', select2:{ placeholder: 'Please Select...', allowClear: true, multiple:'multiple'}, css: { 'jackpot-input-error': BrandIds.error() && BrandIds.isModified() }" multiple></select>
So what I find is happening is the inital valuesretruned from the server in BrandIds get removed. I determine this in the subscribe of the BrandIds. The parameters to the subscribe function look like this
[
{
"status": "deleted",
"value": "cd1f6c04-b7ae-479e-b722-65f837e65ec2",
"index": 0
},
{
"status": "deleted",
"value": "bd66ebe1-080b-4455-9094-bf0464d4adbf",
"index": 1
}
]