Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout.js binding with multiple Select2

My Question is when ever I bind my Select2 with Multiple with Knockout View Model. After selecting one of the options, the data is lost for the second time

KnockOutCode

$(window).load(function () {

ko.bindingHandlers.select2 = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var obj = valueAccessor(),
            allBindings = allBindingsAccessor(),
            lookupKey = allBindings.lookupKey;
        $(element).select2(obj);
        if (lookupKey) {
            var value = ko.utils.unwrapObservable(allBindings.value);
            $(element).select2('data', ko.utils.arrayFirst(obj.data.results, function (item) {
                return item[lookupKey] === value;
            }));
        }

        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).select2('destroy');
        });
    },
    update: function (element) {
        $(element).trigger('change');
    }
};

ko.applyBindings(new ViewModel());
function ViewModel() {
    var self = this;

    self.MetricsModel = ko.observableArray([]);

    GetMetrics();

    function GetMetrics() {
        $.ajax({
            url: '/Admin/GetMetrics',
            type: "POST",
            dataType: "json",
            success: function (returndata) {
                self.MetricsModel(returndata);
            },
            error: function () {
                alert("eRROR GET Applications");
            }
        });
    };

}
$("#application-select-metrics").select2();    
}    

HTML File

    <select multiple="multiple" id="application-select-metrics" class="form-control" data-bind="options: MetricsModel, optionsText: 'Metrics_Name', OptionsValue:'Metrics_ID', optionsCaption: 'Choose...', select2: {}"></select>
@*<select multiple="multiple" id="application-select-metrics" class="form-control">
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    <option>5</option>
</select>*@

Please note that the commented sections, i.e, hardcoded values works, and it allows me to select multiple values, and using Knockout it works for the first time, i get a list populated, but after selecting once, for the second time the data is lost.

Please help,

Thanks,

EDIT: As mentioned by Hanes, I've edited the code, and introduced custom binding, but still it does not work, I dont think the update section of the custom binding is working properly,as the drop down populate once but fails to bind for the second time. Any help would be gladly appreciated.

like image 206
Ronak Jain Avatar asked Jan 15 '14 07:01

Ronak Jain


2 Answers

@rniemeyer threw this up on a JSFiddle not too long ago that should help you out:

http://jsfiddle.net/rniemeyer/R8UF5/

His fiddle, updated

Use the following binding combined with a couple fiddles for when a value is updated:

ko.bindingHandlers.select2 = {
  init: function(element, valueAccessor, allBindingsAccessor) {
    var obj = valueAccessor(),
      allBindings = allBindingsAccessor(),
      lookupKey = allBindings.lookupKey;

    setTimeout(function() { 
      $(element).select2(obj);
    }, 0);
    
    if (lookupKey) {
      var value = ko.utils.unwrapObservable(allBindings.value);
      $(element).select2('data', ko.utils.arrayFirst(obj.data.results, function(item) {
        return item[lookupKey] === value;
      }));
    }

    ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
      $(element).select2('destroy');
    });
  },
  update: function(element) {
    $(element).trigger('change');
  }
};
like image 86
crockpotveggies Avatar answered Sep 22 '22 07:09

crockpotveggies


First, in response to the comments: your code was correct. The JSFiddle done by Jeroen introduced the error in the mocked ajax call: he returned an array of ints, not of objects with the correct attributes. The problem only occurs when the select2 is applied.

Cause

You're applying select2, but select2 is not playing nice with Knockout. And why should it? It doesn't know anything about Knockout and your viewmodel, and it doesn't know how to play nice with it.

Solution

You need a knockout custom binding for the select2 control. A knockout custom binding is the way to create integration between your Knockout code and 3rd party plugins. To write and explain such a custom binding for you would be a bit too much for this answer, so instead I'll give you the following link: https://github.com/ivaynberg/select2/wiki/Knockout.js-Integration

There's a solution that will help you fix the problem. They also link to a JSFiddle, and all in all you should be able to find all you need there. If this one is too complex for you, you might try googling 'select2 knockout custom binding' and see if you can find something less complex.

A reference to the concept of Knockout custom bindings: http://knockoutjs.com/documentation/custom-bindings.html

Good luck!

like image 37
Hans Roerdinkholder Avatar answered Sep 25 '22 07:09

Hans Roerdinkholder