简体   繁体   中英

Select2 with Knockout.js inital value

i use Select2 with knockout.js.

But the control doesn't show the initial value right. It looks like the select function isnt raised

I modified an existing jsbin to demonstrate my problem.

http://jsbin.com/xufovura/6/edit

The binding:

<div data-bind="value: selectedState, select2: { data: states, placeholder: 'Select a State', formatResult: format ,initSelection: initSelect}" class="select2" style="width: 200px"></div>

part of the custom binding (complete code in the jsbin):

ko.bindingHandlers.select2 = {
    init: function(el, valueAccessor, allBindingsAccessor, viewModel) {
      ko.utils.domNodeDisposal.addDisposeCallback(el, function() {
    $(el).select2('destroy');
});

            var allBindings = allBindingsAccessor(),
            select2 = ko.utils.unwrapObservable(allBindings.select2);

      $(el).select2(select2);

    }
};

 function initSelect(element, callback) {
   console.log("initSelect");
          var selectedItems = $.grep(this.states, function (e) { return e.id == element.id; });

           console.log(element);


            callback(selectedItems[0]);
        }

The reason your initSelect function is not invoked is that Select2 thinks that your placeholder is selected. Select2 reads $(element).val() and if that result is falsey then the placeholder is deemed to be selected.

Your div element will always return "" for the val() result.

You should switch the div element to an input element, however when I did this in your jsBin then I found that the input's value had not been initialized by knockout. This is a timing issue with the value binding as the value binding's update function has not yet been invoked when select2 binding's init function is called.

Knockout calls all the init functions first, then the update functions.

Select2 doesn't play nice with Knockout when not using a select element !!

A quick and dirty solution is to make sure that the element's value is set before calling select2 plugin.

init: function(el, valueAccessor, allBindingsAccessor, viewModel) {
  ko.utils.domNodeDisposal.addDisposeCallback(el, function() {
    $(el).select2('destroy');
  });

  var allBindings = allBindingsAccessor(),
  select2 = ko.utils.unwrapObservable(allBindings.select2);

  // Ensure the input's value is set before calling select2
  $(el).val(allBindings.value());
  $(el).select2(select2);      
}

You also don't need the initSelected option anymore, and in fact your fails in the jsBin due to $.grep(this.states, ...) "this" does not refer to the view model at that point.

You also need to take note that allBindingsAccessor changes when moving to Knockout 3.x


The longer and more complete answer involves setting up handlers to various select2 events, and a manual subscription to the backing value to coordinate the manual invocation to $(el).select2('data', ...) when required from the update method of your bindings.

This approach will also be required should you change the backing store to an object instead of just a string value ( ie store the actual "state" object, not just it's id )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM