Knockout.js binding with multiple Select2
Asked Answered
S

2

8

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.

Schoolman answered 15/1, 2014 at 7:6 Comment(3)
Hi mate, my code is correct. I get an array of object from the ajax call. that will inturn populate my MetricsModel. I'm able to make multiple select work for the first time i select any value but when i to select some other value, i get "No matches found" the second time i select. Hardcoding the select with options, it works like a charm.Schoolman
The code is indeed correct. The fiddle was wrong because the mocked data was returned in the wrong format. Updated fiddle: jsfiddle.net/2Q37X/1Headdress
Apologies, my assumptions about returned data were wrong! I've deleted my earlier comment.Amiss
M
9

@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');
  }
};
Miler answered 6/3, 2014 at 5:4 Comment(2)
What does lookupKey do? It always comes out as undefined. I can't find anything about it in the select2 docs.Excurvature
Here's a tweaked version (with updated external reference URLs) which works cascading drop downs. jsfiddle.net/DonovanWoodside/jmtwadu5Perlite
H
2

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!

Headdress answered 15/1, 2014 at 10:22 Comment(1)
Thanks hanes, Is there any thing less complex that you can suggest. All i want to do is that i want to select multiple values using select2 and using jQuery Ajax, I'd push the selected values into my business layer. I've seen the links u've mentioned. feels very complexSchoolman

© 2022 - 2024 — McMap. All rights reserved.