Selectize.js delegated event on option not working

2.5k Views Asked by At

I'm currently trying to listen to click events on generated options inside the dropdown, but I'm currently unable to achieve this.

Since options aren't generated when the DOM loads, I'm delegating the event to the document listening for clicks on the dropdown's options. My code currently looks like this:

var $accountsSelectize = $('#accounts-input').selectize({
  ...
});

$(document).on('click', '.accounts-input-selectize .option', function(event) {
  alert('An option was clicked!');
});

But this doesn't seem to be working. Any idea on why this is happening? Any clue regarding why this event isn't firing at all will be more than welcome.

Edit: Just an FYI, I'm adding a class to the HTML input element, that's why I'm listening for clicks on .accounts-input-selectize .option:

<input type="text" id="accounts-input" class="accounts-input-selectize" placeholder="Search accounts">
3

There are 3 best solutions below

4
On BEST ANSWER

My approach to an admitedly half-baked "solution" is to create a plugin that intercepts the default event listener for clicks on options:

Selectize.define('click2deselect', function(options) {
  var self = this;
  var setup = self.setup;
  this.setup = function() {
    setup.apply(self, arguments);

    // Intercept default handlers
    self.$dropdown.off('mousedown click', '[data-selectable]').on('mousedown click', '[data-selectable]', function(e) {
      var value = $(this).attr('data-value'),
          inputValue = self.$input.attr('value');

      if (inputValue.indexOf(value) !== -1) {
        var inputValueArray = inputValue.split(','),
            index = inputValueArray.indexOf(value);

        inputValueArray.splice(index, 1);

        self.setValue(inputValueArray);
        self.focus();
      } else {
        return self.onOptionSelect.apply(self, arguments);
      }
    });
  }
});

The next step was to initialize Selectize using the previously created plugin, like this:

var $accountsSelectize = $('#accounts-input').selectize({
  plugins: ['click2deselect'],
  ...
});

And that's it.

1
On

The question sounds simple, but its not. The trouble is that selectize prevents all defaults, so at first I wouldn recommend using this lib, but still, if you really want to, there is a way to find out if user changed the option or not.

$('#select-country').selectize({

      //When user selects the widget we'll rememberize its value
      onFocus: function(){
        $(this).data('temp-saved', $('#select-country').val());
      },

      //On blur we check if the value has not changed
      onBlur: function(){
        var previous = $(this).data('temp-saved');
        var current = $('#select-country').val();

        if (current == previous) {
                console.log('NOT changed!');
        }
      },

      //And on change we sure that the value has changed
      onChange: function(current){
            var previous = $(this).data('temp-saved');
            console.log('changed from', previous, 'to', current);
      }
  });

https://jsfiddle.net/mo1Ljm7r/13/

0
On

basing this off NicolasJEngler's self-answer, I've made a microplugin that deselects the clicked-on option. The issue I ran into is this event always gets triggered after an option is added, so you can't tell if it already existed when clicked on. Therefore, I add a class to the option element when clicked/unclicked to check if it's newly added or not.

Hope it helps someone!

/* Selectize deselect function */
Selectize.define('click2deselect', function(options) {
    var self = this;
    var setup = self.setup;
    this.setup = function() {
        setup.apply(self, arguments);
        // add additional handler
        self.$dropdown.on('mousedown click', '[data-selectable]', function(e) {
            let value = this.getAttribute('data-value');
            if( this.classList.contains('checked') ) {
                this.classList.remove('checked');
                self.removeItem(value);
                self.refreshItems();
                self.refreshOptions();
            }else{
                this.classList.add('checked');
            }
        });
    }
});