select2 with closeOnSelect false loses scroll position on select
Asked Answered
C

5

8

Select2 version 4.0.3: When using multi-select of a large list of options with closeOnSelect set to false, I'm trying to select a number of options from the middle of the large list. Each time I select an option the selection items list scrolls back to the first option. I then have to scroll back down the list to find the option after the one I had just selected.

Is there a way to configure Select2 to retain the scroll position after selecting a particular option?

Corpsman answered 10/11, 2016 at 5:5 Comment(0)
L
9

I don't recommend downgrading or modifying the source code, for obvious reasons. The dev has stated that this problem will be fixed in the upcoming update.

For the time being, hooking to the "selecting" and "select" events works fine:

$('select[multiple]').select2({
    closeOnSelect: false
})
 .on('select2:selecting', e => $(e.currentTarget).data('scrolltop', $('.select2-results__options').scrollTop()))
 .on('select2:select', e => $('.select2-results__options').scrollTop($(e.currentTarget).data('scrolltop')))
Lovato answered 8/11, 2018 at 9:3 Comment(1)
Thanks for the pointer. For new visitors - It has been fixed. Just upgrade to version Select2 4.0.12.Gallion
P
7

This is an internal issue with select 2 plugin.

It was a a regression which occurred after the addition of following function, highlightFirstItem(); on option select event

As per the link, https://github.com/select2/select2/issues/4584

the fix to this is to add following condition before executing this function,

if(!(self.options.get('multiple') && !self.options.get('closeOnSelect'))) {
  self.highlightFirstItem();
}

So on select event(on line#1036 in select.js file) becomes, before -

container.on('select', function () {
      if (!container.isOpen()) {
        return;
      }

      self.setClasses();
      self.highlightFirstItem(); 
});

after -

container.on('select', function () {
      if (!container.isOpen()) {
        return;
      }

      self.setClasses();

      if(!(self.options.get('multiple') && !self.options.get('closeOnSelect'))){
        self.highlightFirstItem();
      } 
});

So before highlighting the first element i.e.., resetting the scroll to top we are verifying whether current select2 dropdown has a multi select enabled and closeOnSelect option is not set to false, if any of these is true then highlight first option is not called so scroll is retained on option select

You have to make this edit in the select2.js library as there is no official select2 release with this fix yet. I have used select 2 version 4.0.3 for edit.

Following are the steps, Download select2 4.0.3 zip, from https://github.com/select2/select2/tags

For minification of the source file(select2.js), install nodejs in your local.

Extract the folder, go to dist/js/ open select2.js and replace the container.on('select') function code in code mentioned in after above.

For file minification(uglification), select2 uses grunt, so open extracted select2-4.0.3 folder on command line.

Run following commands, npm install npm install -g grunt-cli grunt uglify

The code changes made above will be moved into select2.min.js file in select2-4.0.3/dist/js folder which you can use as a select2 js file now in your project

Hope this helps

Pommard answered 5/8, 2017 at 20:5 Comment(1)
Good answer... one thing to note is you will also want to do this in the "Unselect" event.Pastille
S
1

After seeing this comment:

https://github.com/select2/select2/issues/4417#issuecomment-256575280

I also downgraded to 4.0.2 from 4.0.3 and it's fixed.

Salyer answered 21/4, 2018 at 4:4 Comment(0)
A
1

Thanks to @Fabian von Ellerts I've managed this with following code in Select2 4.0.3.

$('.select2-multiple').select2({
                closeOnSelect : false,
                allowHtml: true,
                allowClear: true,
                tags: true
            })
                .on('select2:selecting', e => $(e.currentTarget).data('scrolltop', $('.select2-results__options').scrollTop()))
                .on('select2:select', e => $('.select2-results__options').scrollTop($(e.currentTarget).data('scrolltop')))
                .on('select2:unselecting', e => $(e.currentTarget).data('scrolltop', $('.select2-results__options').scrollTop()))
                .on('select2:unselect', e => $('.select2-results__options').scrollTop($(e.currentTarget).data('scrolltop')));
Adige answered 18/8, 2021 at 6:18 Comment(0)
S
0

In Select2 version 3.4.8 It can resolved by commenting this.updateResults() in line no 2933. for more details check bellow code

Before

// multi
    onSelect: function (data, options) {

        if (!this.triggerSelect(data)) { return; }

        this.addSelectedChoice(data);

        this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });

        // keep track of the search's value before it gets cleared
        this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());

        this.clearSearch();
        this.updateResults();

        if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
      ----
      ----
      ---- 
      ----
      ----

After

// multi
    onSelect: function (data, options) {

        if (!this.triggerSelect(data)) { return; }

        this.addSelectedChoice(data);

        this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });

        // keep track of the search's value before it gets cleared
        this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());

        this.clearSearch();
        //this.updateResults(); // comment this line to prevent scroll top scroll bar

        if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
      ----
      ----
      ---- 
      ----
      ----
Scald answered 4/12, 2018 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.