6

I am trying to listen to a Select2 event in a Stimulus controller via the data-action.

I have a stimulus controller, where I have included an event listener for Select2 events, but I cannot listen for the Select2 event from the HTML.

import { Controller } from 'stimulus';

export default class extends Controller {
  initialize() {
    const $element = window.$(this.element);

    $element.select2({
    });

    $element.on('select2:select select2:unselect', (_event) => {
      this.element.dispatchEvent(new Event('change'));
    });
  }
}

I have to listen to the "change" event with the Stimulus data-action attribute, instead of "select2" events. The following code works. Listening via data-action-"select2:select" does not work.

<%= f.select :name, ['name1', 'name2'], data: {'controller' => 'select2'} %>

I would like to listen to events with the data-action attribute, as Stimulus is intended to be used.

Can I listen for Select2 events with Stimulus?

Jesse Farmer
  • 553
  • 4
  • 13
  • 1
    Without adding a wrapper, no. Stimulus only listens for standard DOM events. Where Select2 is an extension of jQuery, [`jQuery.trigger('select2:select');`](https://github.com/select2/select2/blob/4.0.13/dist/js/select2.full.js#L2240), using [`jQuery.Event()`](https://api.jquery.com/category/events/event-object/). For an example on how to force jQuery to dispatch events to the DOM so Stimulus can listen for them see: [jQuery Event delegation](https://gist.github.com/kaspermeyer/7fe28bb7c55c2810e7b5f3d5e67c1a44). Then you could use `data-action="jquery:select2:select->controller#method"` – Will B. Jan 14 '22 at 05:55

1 Answers1

6

I like the approach from https://psmy.medium.com/rails-6-stimulus-and-select2-de4a4d2b59e4

Make one incision into the connect() method of the controller that is responsible for capturing the select2 event and send it back out as a standard change event so that 'data-action': "change->controller#update" will work as expected.

import {Controller} from '@hotwired/stimulus';

export default class extends Controller {
  static targets = ["select"];
  
  connect() {
    $(this.selectTarget).on('select2:select', function () {
      let event = new Event('change', { bubbles: true }) // fire a native event
      this.dispatchEvent(event);
    });
  }

  update(event) {
    console.log("UPDATE");
  }
}
<div data-controller="selector" >
  <select 'data-criteria-form-target': 'select',
          'data-action': "change->controller#update">
</div>
jdwyah
  • 1,253
  • 1
  • 11
  • 22
  • I tried this approach but problem is that in update event I cannot read new value selected in dropdown, I just get nothing if I try $("#my_select_field").val() – Mi Ro Sep 25 '22 at 21:37
  • 1
    @MiRo Works fine for me when I get the value with just plain Javascript using `event.currentTarget.value`. – Timo002 Jan 19 '23 at 10:43
  • 1
    You can get multiple values with: `$(event.currentTarget).val()` – demir Mar 06 '23 at 10:17
  • For me `this.dispatchEvent(event)` its not working right now, i have to change for `this.selectTarget.dispatchEvent(event);` – Pedro Augusto Ramalho Duarte May 26 '23 at 11:41