Chosen: retrieve the UI container from the raw select DOM element

3.1k Views Asked by At

I use Harvest's Javascript library to enhance <select> elements.

https://github.com/harvesthq/chosen

This library creates a <div> element along with the original <select>. This <div> contains the Chosen enhanced UI:

<select multiple id="my-list" class="chosen">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
    <option value="4">Four</option>
    <option value="5">Five</option>
</select>

<div class="chosen-container chosen-container-multi ..." id="my-list_chosen">
    <ul class="chosen-choices">
        <li class="search-choice">
            <span>Three</span>
            <a class="search-choice-close" data-option-array-index="2"></a>
        </li>
        <li class="search-choice">
            <span>Five</span>
            <a class="search-choice-close" data-option-array-index="4"></a>
        </li>
        ....
    </ul>
    ...
</div>

I would like to retrieve this Chosen UI container (the <div>), given that I only know the original <select> element. The challenge is that there may be more than 1 multiple select in the HTML document.

The easy case is when the <select> element has an ID, so the Chosen UI container has the same ID suffixed with _chosen, as you can see in the above snippet.

But Chosen does not require elements to have and ID attribute to work. So what about multiple <select> elements with no ID? What is the proper way to identify the Chosen UI container?

[EDIT] For those who wonder why I can't assume there is an "id" attribute on the <select>: I wrote a small plugin to handle selection order for Chosen, and I can't force users to put an ID on the <select> while Chosen does not require it itself.

3

There are 3 best solutions below

0
Tristan Jahier On BEST ANSWER

Finally I've found a workaround. There is no proper way to get the container provided by Chosen.

[Update] : according to this comment on Github, there is "officially" no proper way to get the Chosen UI element with PrototypeJS.

With jQuery plugin

I've look into the CoffeeScript code of Chosen, and found something interesting. If you're using Chosen plugin for jQuery, the Chosen instance is stored locally thanks to jQuery data() function.

You can retrieve the Chosen UI container this way:

$(my_select).data("chosen").container[0]

The general case

Unfortunately, with PrototypeJS plugin, there is no trick like that.

But we can make an hypothesis in the general case: the Chosen UI container is the first next sibling of the raw <select> element. This assumption is quite strong because, unless something moves the <select> or the Chosen container dynamically, this will always be true.

Here is a not so bad solution, using the 2 different frameworks:

Using PrototypeJS

my_select.next(".chosen-container.chosen-container-multi")

Using jQuery

$(my_select).next(".chosen-container.chosen-container-multi").get(0)
3
Geek Num 88 On

This is not a perfect way to find what you are looking for but it will work most of the time, I would suggest putting an ID on the element or if you dont want to duplicate ids you can use the .identify() method that will put a unique id on the element, you just have to do if before you call Chosen.


If you can find the <select> with a CSS selector you can find the chosen container which is a sibling of that element like this

$$('select').first().next('.chosen-container');
//OR
$$('select.classname').first().next('.chosen-container');
//etc

This depends on the structure of the DOM, which is not a good way to do this normally but Chosen is pretty good about putting the rendered dropdown as a sibling of the target <select> Your mileage may vary

0
felix On

Maybe not exactly what you're looking for, but the instance of chosen is supplied as second argument to the function handling chosen:ready. You could store the reference to chzn.container for later use. The important part is to attach the event handler before calling .chosen(), e.g.:

$(".chosen").on("chosen:ready", function (event, chzn){
    // "this" is the select element
    // "chzn" is the chosen instance
    let container = chzn.container;
    // ...
}).chosen();