select2 / select2

Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
https://select2.org/
MIT License
25.84k stars 6.27k forks source link

DataAdapter (InitSelection deprecation) documentation #3116

Closed Jrizzi1 closed 6 years ago

Jrizzi1 commented 9 years ago

I am attempting to migrate from Select2 3.5.2 to Select2 4.0.0rc1

I have current code which uses InitSelection to prepopulate values

But i see that this is being deprecated which makes sense, initselection focused on input val, where 4.0.0 will be migrating to the select element

The point is, I can find no documentation on how this is accomplished

yellow1912 commented 9 years ago

I think you can check the small piece of code included in the Announcement link

http://select2.github.io/announcements-4.0.html

Personally I really hate this new way of defining custom data loader. It makes the process of defining loader extremely complex especially when you use it with other libs such as angularjs.

What with the $.fn.select2.amd.require? Now suddenly we have to learn about AMD as well.

Knoxvillekm commented 9 years ago

CustomData.prototype.current can't replace initSelection, because you set value only with id prorerty and don't have text. You must manualy create options. (if you use ajax, data is empty)

Easier manualy create options with attribute selected.

P.S. plz add back initSelection

yellow1912 commented 9 years ago

@Jrizzi1

I'm not sure if you have a similar case, but do look into the source code to see how each Adapter works. For example I think select2 SelectionAdapter will scan your selected options and auto add them.

lubosdz commented 9 years ago

This change is really unlucky & developers unfriendly. Previous case when using initSelection was significantly less effort-demanding implementation for developers. There is no documentation with real-world examples (there's only 1 simple example in announcement) and it's really a nightmare to study details of implementation, quite a time loss.

Please provide at least 2-3 more examples on how to initiate dropdown lists for existing values when loading dropdown from remote sources via ajax.

troygrosfield commented 9 years ago

Couldn't agree more with @yellow1912's first comment. What's wrong with this picture:

OLD way:

initSelection : function (element, callback) {
  var data = [];
  $(element.val()).each(function () {
    data.push({id: this, text: this});
  });
  callback(data);
}

NEW way:

$.fn.select2.amd.require(
['select2/data/array', 'select2/utils'],
function (ArrayData, Utils) {
  function CustomData ($element, options) {
    CustomData.__super__.constructor.call(this, $element, options);
  }

  Utils.Extend(CustomData, ArrayData);

  CustomData.prototype.current = function (callback) {
    var data = [];
    var currentVal = this.$element.val();

    if (!this.$element.prop('multiple')) {
      currentVal = [currentVal];
    }

    for (var v = 0; v < currentVal.length; v++) {
      data.push({
        id: currentVal[v],
        text: currentVal[v]
      });
    }

    callback(data);
  };

  $("#select").select2({
    dataAdapter: CustomData
  });
}

We go from 7 lines of code to 30 lines of code to achieve the same functionality? The old way was much cleaner and easier to understand. The new way introduces new concepts (amd) that seems overly complex and confusing.

pjclas commented 9 years ago

I think people are missing the point here (as I was initially). Although 'current' is the replacement for 'initSelection', it is rarely needed at all. From what I understand (and how I've implemented it), the typical way to initialize selections is to set the options elements to selected prior to calling select2. This is easily done in either HTML or AJAX.

It's actually quite easy and much more logical than it used to be. I think the documentation could make this point a bit more clear though because I was also confused at first. You only need this CustomData stuff if you want to override the default behavior of select2, which most people don't.

troygrosfield commented 9 years ago

@pjclas, so based on the example in the release nodes, how would/did you go about easily implementing the solution in 4.0? Can you provide examples? Maybe it's something we all missed...

pjclas commented 9 years ago

Sure, here is a simple ajax example:

http://jsfiddle.net/o45d0td6/

If you aren't using ajax, you can just add the option elements directly to the select tag in the html.

kevin-brown commented 9 years ago

so based on the example in the release nodes, how would/did you go about easily implementing the solution in 4.0? Can you provide examples? Maybe it's something we all missed...

It sounds like @pjclas is referring to the second example in the release notes, which is roughly equivalent to the example in the jsfiddle.

And I agree, the second example is much closer to what most people need to use when migrating. If someone wants to create a pull request that either clarifies that or switches the example, that'd be great.

penihel commented 9 years ago

I believe that all API select2 v4 was very complicated.

Mainly working with ajax.

The InitSelection for me is very important. I understand that even with the tag "select" it must exist.

Imagine the situation. I have only the "id" of the object in my javascript and i need assigns it to "select" to display the information in the version 3.x enough to do that

$ ('#selectIdPessoa').val('BFDC6247-8FCD-4689-A69E-1C7625409924').trigger('change')

Then the ajax (InitSelection) was shot and the component would go to the server and search the "Text".

But in 4.X version nothing happens, even rewriting the code using adapters

I believe that if the API remain so complicated, there will be an exodus of developers for other plugins. We need to simplify things, and quite

penihel commented 9 years ago

The Example here https://select2.github.io/announcements-4.0.html on section "Removed the requirement of initSelection" show how to do without ajax (both examples).

We need a sample of replacement to "InitSelection" with remote data (ajax) on documentation

penihel commented 9 years ago

See http://jsfiddle.net/s8s2ho28/17/

I finally managed to solve my problem in migrating to version 4.

In my scenario all my "select2" are linked to a customBinding the knockoutjs. So I took my customBinding to solve the problem that was previously done by select2 internally on the "InitSelection"

So I'm posting here to help someone who has the same problem.

In the current solution, not yet tested it with "multiple". But soon I will test

ppawel commented 9 years ago

Yeah I'm thinking about migrating from selectize.js to select2 4.0 but the new API looks extremely overengineered...

kevin-brown commented 9 years ago

I figure I might as well reiterate that most use cases do not need a custom data adapter, including pre-selecting options using AJAX.

For those few that do, we need some actual documentation. I've been looking into Docco for generating some more direct documentation automatically, but there are plans to overhaul the documentation.

We need a sample of replacement to "InitSelection" with remote data (ajax) on documentation

The second example under that same section is designed for AJAX use cases, which was mentioned above.

ppawel commented 9 years ago

Well the data adapter issue is obvious to solve and people crying for initSelection to be brought back really should just RTFM. However I'm referring to the general idea with adapters/decorators and wrapping that in this AMD thing. It really makes integration between select2 and Angular for example that much harder when you have to deal with another layer of dependency injection stuff.

Anyway, what's done is done, perhaps we'll get used to it.

jackbit commented 9 years ago

Data Adapter is stressful solution, spend hours to understand it plus trials-errors. Well my monkey patch isnt good, but at least it works without bleeding to Data Adapter

 $.each $(el).find('.select2-ajax'), (i, item)->
      $(item).select2
        ajax:
          url: $(item).data('url')
          dataType: 'json'
          delay: 250
          data: (params)->
            return {q: params.term}
          processResults: (data, page)->
            return {results: data}
          cache: true
        minimumInputLength: 3
        templateResult: (data)->
          return data.label
        templateSelection: (data)->
          return data.label
      ajax_selected = $(item).parent().find('.select2-selection__rendered')
      if ajax_selected.length
        ajax_selected.text(ajax_selected.attr('title'))
        $(item).parent().find('.select2-container').css('width', 'auto')
kevin-brown commented 9 years ago

@jackbit If you used text for your template (you should be - it's mostly required) you likely wouldn't need to fiddle with how it is automatically rendered.

Alternatively, if you don't feel like doing the re-mapping, you should fall back to data.text in your templateSelection.

templateSelection: (data) ->
  return data.label or data.text
templateSelection: function (data) {
  return data.label || data.text
}

And you can set the width to auto by default when initializing Select2.

width: null // or 'auto', both are equivalent
jackbit commented 9 years ago

@kevin-brown I have been using templateSelection on my snipped code above. My issue was when I want edit selection that i have already set or save, it doesn't display default value that i have made before. But in original select tag, it has my selected value.

penihel commented 9 years ago

In my opinion. We already use the "selec2" one day we will get used to the new API and everything will work out.

But my concern is that the use of a plugin should be as simple as possible. And definitely this is not happening in the new API, and the consequence of this is that new users do not opt ​​for our plugin, and over time the "select2" come into disuse.

I think we should simplify much the API plugin. Mainly in integration with AJAX.

The end of InitSelection brings disastrous consequences for those who used the plug connected to a MVVM framework (knockoutjs, angularjs and etc ...). For a task that "select2" made automatically, should now be made in advance by the application code itself.

See my example: http://jsfiddle.net/s8s2ho28/17/

In Version 3.x I used the InitSelection and voila, problem solved by integrating with knockoutjs I just attributing the value of the element and the "select2" resolved to me how to display it properly (searching via ajax text)

In 4.X version now after a long time to understand where it should be done to change (trying with or without DataAdapters) I managed to get a solution. But now my application via ajax search text, and then everything is already in HTML ready, oh then I apply the plugin.

It works, but makes using more painful, and it does not attract users, and it amazes beginners programmers.

I love the plugin, do not want to change it, so I think we should prioritize better documentation, especially a simpler API.

but, this is only my opinion, and not based on technical arguments, but rather on the user experience (developer)

troygrosfield commented 9 years ago

@penihel, many share the same opinion and to your point about being turned off with the new api, I ended up downgrading back to 3.5.x.

It's not a matter of being able to figure out how to make it work, it goes back to the beginning of why we choose to use the library in the first place.... Ease of use and a simple, not overly complex, api that new developers can pick up without having to look at code and scratch their heads.

Zxurian commented 9 years ago

I'm also running into a problem with pre-setting selections via ajax but also using templateSelection & templateResult based on ab object returned via ajax.

How would I preset options in a multiselect with a known data object ahead of time that filters into the templateSelection?

pjclas commented 9 years ago

I'm seriously confused about why everyone is having problems here. Kevin made the initSelection process way simpler and more logical with select2 4.0. He has two examples that show how to do it with or without ajax as he's mentioned several times. I think anyone who thinks they need a custom DataAdapter probably doesn't understand the simplicity of the new design...

Step 1: Statically or dynamically create/change options in a select element. Step 2: Trigger a change on the select2 interface. Step 3: Realize how easy this was and stop complaining! :-P

penihel commented 9 years ago

Friend @pjclas.

You do these three steps is not so simple, especially for those who are now beginning to use the select2.

And in the previous version, these three steps were all made using settings when applying the "select2" to the element.

Now this version you have to do some steps before applying the "select2". And some scenarios it sharply affects the quantity and complexity of code.

In my scenario I have a system with a 40 "select2" different, I have to do a treatment on each to ensure that there is the element "option" within the element "select" before applying the plugin "select2". (I do this for an ajax request and apply the "select2" in callback)

Even with a seemingly simple step, in various scenarios it is a painful step.

As you said, to use the select2 now we need (at least) the steps 1,2 and 3.

In the previous version it was solved in just one step. And lose this characteristic is not advantageous for the "select2" in my opinion

Another example, show me an example of how to change the CSS class Dropdown element without using Adapter? In the previous version there was a property, now only using the full version.

pjclas commented 9 years ago

You don't have to have everything created prior to creating the select2, you can modify it any time you want, and then simply trigger a change event by calling "$select2_element.trigger('change');". As far as the CSS goes, you can change that at any time like you can with any element...

kevin-brown commented 9 years ago

I'd think there would be a more difficult time converting the <input /> to a <select>, and maybe that's inspiring some of the issues here, as that is what requires the most changes in the long run. I wouldn't mind finding possible solutions to making migration easier, but stopping the deprecation is not a realistic long-term solution.

You do these three steps is not so simple, especially for those who are now beginning to use the select2.

Admittedly, that's my current issue with the solutions that are out there: It's no longer a "try initSelection and hope it works" kind of situation. So far we've solved the "hope it works" part of that, now it's just time to make it easier.

In my scenario I have a system with a 40 "select2" different, I have to do a treatment on each to ensure that there is the element "option" within the element "select" before applying the plugin "select2". (I do this for an ajax request and apply the "select2" in callback)

I'd hate to suggest "wrap it up in a helper function" as a possible solution here, as that adds an additional (albeit small) step to initializing Select2. But it might not be that much code, considering the small amount of code currently in there for compatibility that handles the job (somewhat) well.

The end of InitSelection brings disastrous consequences for those who used the plug connected to a MVVM framework (knockoutjs, angularjs and etc ...). For a task that "select2" made automatically, should now be made in advance by the application code itself.

I think it might just be sheer luck, but for some reason I haven't heard of a ton of issues converting Angular and Ember apps. Perhaps it's because Angular has other (better suited, imo) alternatives and Ember actually has a distinct "set everything up ahead of time" step that people are used to.

Part of my issue with Knockout, which is why I can't help a ton when converting it, is that I'm not at all familiar with what common conventions are. I can't speak for where application preparation happens with it, but I do know that it has the ability to synchronize data through bindings. And that should automatically create a new <option>, which Select2 should be able to pick up on.

But again, it's unfamiliar territory for me.

show me an example of how to change the CSS class Dropdown element without using Adapter?

The dropdownCssClass option still works in the full builds of 4.0.0, it's not yet documented though.

penihel commented 9 years ago

Hi @kevin-brown you're the best.

I think you understand my point.

I also think that the direction is not returning to the depreciated methods.

I believe that the direction is to facilitate as possible adding simpler options such as the placeholder (example: css changes, container)

and greatly improve the documentation. We need to understand that most people who use select2 not know concepts such as "decorator", "adapter" and "amd"

Thanks for listening, and sorry the heated argument. My intention has always been to contribute to the plugin, not just criticize negatively.

Zxurian commented 9 years ago

@kevin-brown I also agree with not moving backwards, and I can see wanting to use methods on the original select element when setting the values of said select element as it's more intuitive, but with all the examples I've seen so far, none of them deal with handling setting an option via an object and letting templateSelection display it like it should.

Example http://jsfiddle.net/q1q00hnm/3/ (ajax example from options page modified to show image in selection) How would you pre-set, or set after intializing, a value in that select2 with a known repo object contacting the data for the selection? {id: 1, full_name: 'test repo', owner: { avatar_url: 'test_image.jpg' } }

wintersommer commented 9 years ago

We did it !. We came up with this solution for the AJAX problem ( Init with default value without < option > html tags (just < select > < /select > in DOM) and this data adapter: (select2 4.0)) This is done with Typescript.

!! Key point ONE: don't save the current values on the select element with $.val() as the options come from the ajax call. Val() does not work on non existing dom options - we save and read current selected value with: LINE: (set value) ($(this.el)).data('selectedValues', [options.value]).trigger("change"); LINE (read value) : var currentVal = this.$element.data('selectedValues');

!! Key point TWO: The result data from the ajax request musst be returned as a collection data.results property:
LINE: callback({ results: mapped });

///

class Select2View {

el:any;

constructor(options?) {
    console.log('constructor of select2wrapper');
}

showselect2(options?) {

    this.el = options.el;

    console.log('init with value:', options.value);

    (<any>$).fn.select2.amd.require(['select2/data/array', 'select2/utils'], function(ArrayData, Utils) {
        function CustomData($element, options) {
            (<any>CustomData).__super__.constructor.call(this, $element, options);
        }

        Utils.Extend(CustomData, ArrayData);

        CustomData.prototype.current = function (callback) {

            var data = [];                
            var currentVal = this.$element.data('selectedValues');

            console.log('current',currentVal);

            if (currentVal == null) {
                callback([]);
                return;
            }

            if (!this.$element.prop('multiple')) {
                currentVal = [currentVal];
            }

            for (var v = 0; v < currentVal.length; v++) {
                data.push({
                    id: currentVal[v],
                    text: currentVal[v]
                });
            }

            callback(data);
        };

        CustomData.prototype.query = function (params, callback) {
            console.log('query',params);                

            (<any>$).ajax({
                url: "/myapi/layouts/5"                    
            }).done(function (data) {

                var mapped = $.map(data.Layout, function(obj) {
                    return { id: obj.Key, text: obj.Key };
                });

                callback({ results: mapped });
            });
        };

        (<any>$(options.el)).select2({
            dataAdapter: CustomData           
        });
    });

    (<any>$(this.el)).data('selectedValues', [options.value]).trigger("change");      
}

}

export = Select2View;

---------------------- snip -------------------- ps: remove the <....> typings from typescript to get javascript ps2: the options Methode parameter is just used to configure this class from the outside

kevin-brown commented 9 years ago

Another one of my near-future goals is to get a pull request going that switches the style of the documentation, so it focuses more on working examples and less on explanations about them.

none of them deal with handling setting an option via an object and letting templateSelection display it like it should.

One thing I've considered off and on for the past 21 days is the idea of converting the data attributes on the <option> into properties on the data object. That could mean that an <option> like the following

<option data-test="this" value="1">Something</option>

would automatically be converted into a data attribute with the test property

{
  "id": "1",
  "text": "Something",
  "test": "this"
}

Which is something we already do for data attributes on a <select>, and most likely would not be difficult to bring over as well.

The other alternative is to just allow an "extra data" property on an <option> and automatically combine it with the generated data object, which would allow for freeform JSON as long as it can be parsed by jQuery.

penihel commented 9 years ago

I like your last idea. the "extra data"

Today we have a problem. When you start ajax select2 with a default initial option tag and seek method

$ ('select'). select2 ('data')
// output: {id: xxx, text: yyyy}

After I seek any other item via ajax, and call the same method:

$ ('select'). select2 ('data')
// output: {id: xxx, text: yyyy, myprop1: zzz, myprop2: 2334}

I (and I think everyone else) need to always return the object always as shown in the second example

// output: {id: xxx, text: yyyy, myprop1: zzz, myprop2: 2334}

Because we need the object with all properties completed for use elsewhere in the html page.

This is one reason that the late "InitSelecion" was useful, he guarantee that every time I call the "data" would return me whenever my entire object received from the ajax request.

Now including a initial default select tag, to call the "data" will return me a different object.

You could understand the problem?

ttucker commented 9 years ago

converting the data attributes on the

I would love to see that implemented, as it seems it could solve peoples' problems with initSelection's demise, as well as allowing more flexibility in handling events and to make use of richer or more complex data.

Zxurian commented 9 years ago

@kevin-brown, The data-* options are a possibility but you'd have to have a syntactically safe way of describing nested objects within the data attributes

Example: how would {id: 1, full_name: 'test repo', owner: { avatar_url: 'test_image.jpg' } } be described in multiple data-attribute fields.

One option would be to just fit the entire JSON (escaped) into a single data field on the option, and have it be parsed by the templateSelection option when initially rendering

    <select>
        <option data-select2-option="{id:1,full_name:\"test repo\",owner:{avatar_url:\"test_image.jpg\"}}" selected></option>
    </select>

However neither option I think solves the underlying issue, or an associated issue I just thought of. My thinking is this, if there's already a method templateSelection built into select2 to take a selection object (that being clicked on in the dropdown) and return a jQuery object or string to populate the select2 element itself, why couldn't that be called by itself instead of only being able to be called from clicking an item on the dropdown list. Something as simple as $(element).select2('manual-select', obj) or similar that would basically be the same as if an ajax search had occured and a user selected a returned data object.

The associated issue is this, say I have two dropdowns, (forked from first demo: http://jsfiddle.net/zvgjLLkh/2/ ). And I wanted to programatically set the second select based on picking an option from the first one (or vice versa). There's no way, (and if I'm wrong please let me know), to pass an object to either select that would pass it through the templateSelection before rendering it.

Both would be solved by having a manual selection method.

Zxurian commented 8 years ago

I've put a really ugly hack together for manual selection. On the current v4.0.0 build of select2.full.js starting at around line ~5841

      } else if (typeof options === 'string') {
        var instance = this.data('select2');
        console.log(instance);

        if (instance == null && window.console && console.error) {
          console.error(
            'The select2(\'' + options + '\') method was called on an ' +
            'element that is not using Select2.'
          );
        }

        var args = Array.prototype.slice.call(arguments, 1);

        /**
         * Added by RG for temporary bandaid to manually select select2 options
         */
        if (options == 'manualSelect') {
            instance.trigger('select', {
                data: args[0] 
            });
        }

        var ret = instance[options](args);

        // Check if we should be returning `this`
        if ($.inArray(options, thisMethods) > -1) {
          return this;
        }

        return ret;
      } else {

usage is just $(element).select2('manualSelection', obj) where obj is the object data that you want to select / add to the multi-select.

304NotModified commented 8 years ago

I agree with others, the new dataAdapter way is over-design and really horrible. The docs are really unclear (it's deprecated, but still moved? It seems a breaking change, which is deprecated...) and this is really annoying.

We hope this will be improved in a new version. For now we reverted the upgrading process (moved back to 3.5)

banesto commented 8 years ago

I was able to preset original multiselect values this way:

  1. set up data attributes on option
<select id="subjects" name="subjects" multiple="multiple">
  <option value="62501" selected="selected" data-display-name="Ask your colleagues" data-image-url="#{image_url}"Ask you colleagues</option>
</select>

and in the templateSelection template function:

var attrData = {};

$(item.element.attributes).each(function() {
  if ('data' === this.nodeName.substring(0, 4)) {
    // remove "data-" prefix and convert dashes to underscores
    return attrData[this.nodeName.substring(5).replace("-", "_")] = this.nodeValue;
  }
});

_.extend(item, attrData);

This way all the option attributes are available for formatting selection item.

juanitoddd commented 8 years ago

I faced the same problem: Pre-selecting some value when using a multiple tag, Ajax query select.

What I did was, write the option tag to the select,

<select id="mySelect">
           <option value="1">Pre-selected tag</option>
</select>

and then after building the Select2, call the trigger('change') like this:

$j('#mySelect').select2({
            ajax: {
                ....      
              }
        });
$("#mySelect").val("1").trigger("change");

This added the tag to my select

iSuslov commented 8 years ago

Ridiculous! How come I need to spend hours understanding how to preselect value

304NotModified commented 8 years ago

Will this point be improved in the future?

SimonMoua commented 8 years ago

Hi juanitoddd, thank you, but this only select 1 value (even if I call this many times for different options), because in the select2.js file, it clear the "ul" on update (by calling $this.clear(), which get the "ul" and .empty() it). BUT! I see that when we manually select, it's not disappearing because it actually recreate all the "li" using the attribute "data" (which must be empty when we call .trigger("update") like you prescribed.

By the way, I can bypass all that by changing "MultipleSelection.prototype.clear" in the select2.js directly (changing the clear to NOT remove the initial options), but as it is "unclean" and a bypass of the natural behavior of this function, I would like to be legit (and now those options are immortal and have to be handled manually... it's a mess).

Also, saying .select2('data', anArrayWithMyValues) does not work... Maybe I do THAT wrong..

So.

Do you know how to populate "data" with the function .trigger("update"), or do you know of a way to simply have more than one pre-selected option in a multiple select2?

Thanks!

moacir-selinger commented 8 years ago

Hello everybody, I initiated an activity to migrate Select2 to version 4.0, but it's hard just to contribute in conversation, I use to AngularJS and we have some complementary implementations because the needs of our systems, and use this new version is not giving right. I am unable to apply all current resources, not to mention some limitations on the types mentioned above.

We love this feature and use it to its maximum power, but the new version is killing us. We are going back to 3.5, let's wait a while and see how the new updates will walk and try again in the future.

Thanks guys for conversation.

rhythmnewt commented 8 years ago

Also rolling back to 3.5

sujeshkumaruv commented 8 years ago

@juanitoddd : Doesn't your ajax stop working on that step ?

glowysourworm commented 8 years ago

+1

I'm also creating an AngularJS wrapper for this control and was extremely happy with it until I realized there was absolutely no easy way to programmatically control the data - which should be the most basic operation on the API. (due to the DOM searching of the API)

I'm finding using a data adapter isn't working with Ajax because it's searching through the DOM for results..... which aren't there because they're remotely queried.... seems kinda basic? C'mon guys

(to be more specific the initial value won't set because the DataAdapter.current method is searching through the DOM for a value that isn't there yet)

Framnk commented 8 years ago

+1 in the hopes this gets better in the next version.

In my case, I am using the DataAdapter method because I'm dealing with a large data set that I need to do paging/filtering on. However I've spent hours trying to figure out how to get the initial selection to populate correctly (still with no luck).

That said, I realize this is free software and I am not contributing to it so keep up the good work :)

bonesoul commented 8 years ago

will this ever get fixed?

jzabroski commented 8 years ago

This is so confusing. This is my fifth time reading this page in the past month.

304NotModified commented 8 years ago

And it doesn't look like this will ever get improved...

jzabroski commented 8 years ago

My major problem with this API is there is no way to access the data context. You are expected to construct it entirely from within the data adapter. Which means it is not a true adapter. It is a one-direction plug.

The most immediate fix would be to allow the constructor for this object to take two additional, optional, parameters:

But the problem with even this is there is no way to handle asynchronous data loads using this paradigm, which is EXACTLY WHY all the docs basically tell you to work around anything ajax-related by first inserting your options elements using AJAX, and THEN calling select2. But that defeats the purpose of a modern data-bound UI where you don't know the ID of the element, and are only using select2 to add a little bit of jazz to the UI.

Just my 2 cents after spending all day at work on a Friday trying to figure out a solution to this.

jzabroski commented 8 years ago

Here is the exact problem: https://github.com/select2/select2/blob/4.0.3/src/js/select2/core.js#L31

I think we may be able to build a proxy for initSelection and make a backward compatible fix for 3.x users if we just pretend that initSelection was never removed from the options object. Consumers may have to slightly modify their initSelection code, and we'd have to provide a BackCompatInjectedAdapter extension that drives this logic, but the wonky idea would be you would call it like this:

$("#example).select2({
  dataadapter: BackCompatInjectedAdapter,
  current: [this.KnockoutObservableStoringCurrentOptionId()];
});

Going to try that next... there HAS to be a way as part of the options object to specify a current value.

jzabroski commented 8 years ago

OK, here is where I am at with my attempt at a workaround. I tried writing my own custom data adapter, and gave up after TypeScript kept complaining. The whole way Select2 does modules is too advanced for me to figure out how to integrate into TypeScript.

So, here is what I did instead to progress my idea. I edited select2/data/select.js, as that is where current prototype function is defined.

I changed the function to the following, but I am still not getting select2 to set the current element (obviously, this is bad code, but I am trying to understand what 'current' is really doing for me that needs so many layers of indirection:

  SelectAdapter.prototype.current = function (callback) {
    var data = [];
    var self = this;

    var ic = this.options.get('initCurrent');
    console.log(ic);
    if (typeof ic !== "undefined")
    {
        data.push(new Option(ic, ic, true, true));
    }
    else
    {
        this.$element.find(':selected').each(function () {
            var $option = $(this);

            var option = self.item($option);

            data.push(option);
        });
    }

    callback(data);
  };