javascriptjqueryangularjsangular-chosen

Dynamically generating Ids for option elements with Angulars' Chosen


We are currently using chosen (https://harvesthq.github.io/chosen/) to generate a multi-select drop down. Our template looks something like this:

<label class="label">Our Section Header</label>
<div class="twoColMultiSelect">
  <select multiple chosen ng-model="formCtrl.List" ng-options="info.value for info in formCtrl.List | filter:{type : formCtrl.Types.TYPEWEWANTFORTHISPAGE}" data-placeholder="Select Field(s)">
  </select>
</div>

The above code shows us getting the list from our controller, filtering the information from the list which is then displayed as the options of the select.

This generates html like this:

<div class="chosen-drop">
  <ul class="chosen-results">
    <li class="active-result" style data-option-array-index="0">info item 1</li>
    <li class="active-result" style data-option-array-index="1">info item 2</li>
    <li class="active-result" style data-option-array-index="2">info item 3</li>
   </ul>
</div>

For the purposes of selenium testing I need to add id attributes to the list items. Is there a way to do this with angular or chosen?

What I'd like is something like this:

<div class="chosen-drop">
  <ul class="chosen-results">
    <li id="info-item-1" class="active-result" style data-option-array-index="0">info item 1</li>
    <li id="info-item-2" class="active-result" style data-option-array-index="1">info item 2</li>
    <li id="info-item-3" class="active-result" style data-option-array-index="2">info item 3</li>
   </ul>
</div>

I currently have a solution which works by getting the elements in the DOM and generating the ids after the page has loaded but this seems overly complicated.

Thanks

UPDATE

lin, after some prodding, provided a link to a SO question about why you shouldn't mix AngularJS and JQuery: "Thinking in AngularJS" if I have a jQuery background? The exchange between the top answer writer and the top commenter to that answer contains the following exchange:

"I'm not rewriting FancyBox in jQuery to keep a pure Angular app." - top commenter

"Most jQuery plugins can be rewritten in AngularJS cheaply...if you can't think of a solution, ask the community; if after all of that there is no easy solution, then feel free to reach for the jQuery" - top answerer

So to clarify my question, is there a solution to my problem that would not require me to rewrite this jQuery plugin?

For clarity, and to hopefully avoid another exchange like the one I had with lin - I am working as part of a team. I do not have the remit to rebuild the application. I was asked to perform a single specific task. I am working within the constraints of the management of my team. I am not going to quit my job over design decisions on a front end application or over a management decision that I, as a back end developer, was asked to look at the front end.


Solution

  • One way to achieve this is to edit the chosen.jquery.min.js file. The file contains a method:

    Chosen.prototype.choice_build = function (b) {
                var c, d, e = this;
                return c = a("<li />", {"class": "search-choice"}).html("<span>" + b.html + "</span>"), b.disabled ? c.addClass("search-choice-disabled") : (d = a("<a />", {"class": "search-choice-close", "data-option-array-index": b.array_index}), d.bind("click.chosen", function (a) {
                    return e.choice_destroy_link_click(a)
                }), c.append(d)), this.search_container.before(c)
            }
    

    I edited this to include an id attribute, something like:

    Chosen.prototype.choice_build = function (b) {
                var c, d, e = this;
                return c = a("<li />", {"class": "search-choice"}).html("<span id= '" + b.html + "'>" + b.html + "</span>"), b.disabled ? c.addClass("search-choice-disabled") : (d = a("<a />", {"class": "search-choice-close", "data-option-array-index": b.array_index}), d.bind("click.chosen", function (a) {
                    return e.choice_destroy_link_click(a)
                }), c.append(d)), this.search_container.before(c)
            }
    

    Obviously in this specific example there is the danger that the html is not unique (potentially quite likely) so the ids won't be either (though you can get around this quite easily by including other information in that id like b.array_index).

    Another potential danger is that this will affect all of the drop downs on your page, so if you only want them in specific places a more elegant solution is required.

    Edit

    Should mention that more methods will need to be changed - the above is an example of one such method. Look for the elements you want to add ids to in this file and edit them here.