Add decorator to data adapter in Select2 version 4.x
Asked Answered
B

1

3

I want to support the MaximumInputLength decorator for my custom Select2 Data Adapter. In my custom data adapter, the Utils.Decorate() call does not do anything.

Looking at this gist, I could call the Decorator function in the same place where I initialize select2(), but that seems icky and not DRY, as I want to initialize many of these Select elements.

In order to enable minimum input for ALL instances of MyDataAdapter, is it possible to decorate that adapter from the adapter itself? Is there a better way to do this?

My select2() call:

$('select').select2({
    dataAdapter: MyDataAdapter,
    minimumInputLength: 2
});

MyDataAdapter (sans dependencies):

define([...], function(Utils, MinimumInputLength, ArrayAdapter){

    function MyDataAdapter($element, options) {
        this.$element = $element;
        this.options = options;
        MyDataAdapter.__super__.constructor.call(this, $element, options);
    }

    Utils.Extend(MyDataAdapter, ArrayAdapter);
    Utils.Decorate(MyDataAdapter, MinimumInputLength); <-- does nothing

    MyDataAdapter.prototype.query = function(params, callback) {
        console.log('query!');
    };

    return MyDataAdapter;

});
Berkeley answered 3/6, 2015 at 21:24 Comment(0)
I
9

You'll notice in the gist that their call to decorate their adapter looks like

var dropdownAdapter = Utils.Decorate(
  Utils.Decorate(
    DropdownAdapter,
    DropdownSearch
  ),
  AttachContainer
);

And they later go on to use dropdownAdapter when initializing Select2. This is because Utils.Decorate returns the decorated class instead of decorating it in-place. You'll also notice that it does this after the decorator and adapters have already been created.

So instead of calling Utils.Decorate in the middle of your adapter, you should call it at the end. Either when you are returning the finished adapter, or right before you do.

define([...], function(Utils, MinimumInputLength, ArrayAdapter){    
    function MyDataAdapter($element, options) {
        this.$element = $element;
        this.options = options;
        MyDataAdapter.__super__.constructor.call(this, $element, options);
    }

    // Always extend after making the constructor
    Utils.Extend(MyDataAdapter, ArrayAdapter);

    MyDataAdapter.prototype.query = function(params, callback) {
        console.log('query!');
    };

    // Decorate after the adapter is built
    return Utils.Decorate(MyDataAdapter, MinimumInputLength);
});

Before your major issue was that you were not using the returned class from Utils.Decorate. But the other issue that you would have hit is that it just wouldn't work, which was because you were overriding the query method after it had been decorated.

Inventor answered 3/6, 2015 at 22:24 Comment(3)
"Either when you are returning the finished adapter, or right before you do." how would I do this right before I return, rather than returning the Utils.Decorate() call?Berkeley
@BenjaminSmith If you wanted to assign the result to a variable, do something extra with it (or something else), and then return that variable it would work as well.Inventor
Is there a "complete" working script for this functionality? I was hoping to separate the select initialization from the decoration as well.Fantinlatour

© 2022 - 2024 — McMap. All rights reserved.