How can I add a custom button to each entry in the "results" dropdown?

greetings… :slight_smile:

I’m building a fancy Select2 based system for creating custom time window ranges, I’ve got 90% of it working, but I’m struggling with the last part of it…


my markup is being generated on page load, with the following bare minimum structure:

<select title="Select your time window here, enter a name to create a new entry." name="time_window_name">
  <option class="internal-option"></option>
  <option value="custom" disabled="disabled" class="internal-option">Custom Window</option>
</select>
  • the empty option here is used by Select2 as a placeholder for “no selection”.
  • the “Custom Window” option is used by my logic to show when either a “start” or “end” time input field has a value (not shown here).

when a new <option> is added to the source <select> element, it appears in the list as per the following two examples:

<select title="Select your time window here, enter a name to create a new entry." name="time_window_name">
  [ snip... ]
  <option value="7,8">Morning Rush</option>
  <option value="16,17">Evening Rush</option>
</select>
  • where the option’s value refers to startHour,endHour.

I’m initialising Select2 with the following config:

{
  allowClear: true,
  placeholder: "no filter",
  tags: true,
  createTag: createTagHandler,
  templateResult: templateResultHandler,
}

where createTagHandler just does some basic checks (valid name, at least start or end time, etc) and templateResultHandler modifies the rendered select result entries as follows:

function templateResultHandler(state) {
    if (!state.id || ["custom"].includes(state.id)) {
        return state.text;
    }

    const item = $("<div>", {
        class: "select2-result-item d-flex align-items-center",
    });
    $("<span>", {
        class: "select2-result-item__text",
        text: state.text,
    }).appendTo(item);

    const deleteButton = $("<button>", {
        type: "button",
        class: "btn btn-danger btn-sm ms-auto",
    }).appendTo(item);
    $("<i>", {
        class: "fa fa-trash",
    }).appendTo(deleteButton);

    return item;
}
  • note: the select2-result-item classes seen here were suggested by other resources that I’ve found online, not sure if they are helping or not.

the end result (with extra “start hour” and “end hour” inputs) is a UI that looks like this:

2023-06-09 10_29_16-WebIT 2.0.0-SNAPSHOT.7


the crux of my issue here, is that I cannot figure out how to get a custom event handler bound to the custom <button> element that I’m adding to each option… no matter what I try, Select2 always takes a click anywhere on the option item as “selecting that option”, even if I click the button I added.

I’ve tried event.preventDefault() and event.stopPropagation() in the “click” handler, I’ve tried attaching the handler to different parent elements, I’ve even tried hooking into and overriding the select2:select handler… I cannot get Select2 to not select the item when I click my custom button.

please can someone help me out here? what am I missing??

alrighty, eventually managed to solve this one… no thanks at all to the documentation, but rather from a (now somewhat old) StackOverflow answer.

the gist of it, is to listen for the select2:selecting event first, then check which DOM element was clicked to trigger the current selection process, located at event.params.args.originalEvent.target, and if it’s my custom “delete” button, then simply call event.preventDefault() and the select2:select event that would normally fire next is cancelled.

nice and clean and simple… wish the documentation on Select2 event handling was a little clearer, could’ve saved myself a few days of hed bashing.

wow, so this forum is dead… lol. just got a “activity summary since your last visit” email, which lists this as the one and only new thread.

meh. whatever. I’ve used Select2 for years now, but without much effort I’m already finding newer alternatives with much better documentation and much more active communities, so… mkaybyenow.