5

I have a progressively enhanced <select> element in HTML.

It uses the following form,

<ul>
  <li></li>
  <li></li>
  ...
</ul>

With the current implementation, the click event handler is attached to every li element.

Will this create a problem when you have, say, about 1000-2000 elements, will it be slower as compared to attaching a single event handler to the <ul> and picking necessary information from e.srcElement?

Current implementation:

There is the whole list of

<div>
  <select>
    //1000-2000 elements
    <option> </option>
  </select>
  <ul>
    //Mapping the values of the 1000-2000 option tags
    <li> </li>
  </ul>
</div>

The click event handler maps the selected li to its equivalent option, sets that as the selected item and triggers the change event for the select.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
painotpi
  • 6,894
  • 1
  • 37
  • 70
  • 2
    Event handlers consume memory. Attaching the event to the `
      ` makes sense here, but without seeing what the event handler is doing, it's hard to for sure say that it is the best route. I can't imagine that it would be better to attach it to each `
    • ` though, since you already have a reference to the clicked `
    • ` in the event object.
    – crush Dec 18 '13 at 13:37
  • in any way, it is better to load elements dynamically, but not all at once. Think about creating an a select with search field, and load only part of options. – pomaxa Dec 18 '13 at 13:40
  • 1
    @pomaxa I've been in situations where loading dynamically slowed down the user's experience too much (waiting on the AJAX HTTP requests to complete). Instead, I loaded all of the data into a Javascript array object, and held it in memory. Rather than create all of the DOM elements for all elements of the array, I simply created 20 DOM elements, and displayed only 10 on the screen. I then took a slice of the Javascript array and populated these 20 DOM elements as the user scrolled. I found that creating 1000's of DOM elements up front really puts a burden on IE's rendering engine. – crush Dec 18 '13 at 13:43
  • 1
    @crush, it's always up to the task, what exactly to do. I prefer to store data in json object, cuz it easier to search in it, and save it after first load in localStorage; even for IE6 you can use window.title as localStorage; And load only elements you need; Load all needed elements into DOM is to expansive in my opinion. if 1000 or 2000 elements is max, than it is ok. But if you think, that there maybe a case with > 20k elements. Then it is an issue; In my experience, nobody will scroll select with 100+ elements. they are start pressing letters on keybrd or look for search input. – pomaxa Dec 18 '13 at 14:07
  • @pomaxa I didn't know that about `window.title`. I'll have to try that out. Thanks for the info. And yes, I agree, most would just start hitting keys. Good points. – crush Dec 18 '13 at 14:45
  • @crush I've updated the question with the current implementation I have. – painotpi Dec 19 '13 at 07:06
  • @pomaxa right now I have the search feature in place (using regex). will try to setup a fiddle. – painotpi Dec 19 '13 at 07:08
  • Use `.on()` on the parentElement http://stackoverflow.com/questions/9122078/difference-between-onclick-vs-click#answer-11878976 – EricG Dec 19 '13 at 09:03
  • @crush any way I can find the amount of memory it will consume? – painotpi Dec 19 '13 at 10:21
  • @TarunPai Just 1 handler, see example x) – EricG Dec 19 '13 at 10:32
  • @TarunPai - if you have a search feature, try to change the dom inside select, on search field change, or scroll down/up event; In real life you need only 40 items pre one-time, if all data is stored in js memory it will be almost instant to update data in select; – pomaxa Dec 19 '13 at 11:39

4 Answers4

3

First of all, 1000-2000 DOM nodes that toggles might be a problem on its own, regardless of how you attach click handlers.

It is generally good practice to delegate events, but not too far. The closest common ancestor that share the same functionality is most often the best.

I have doubts that using one event handler for each child element will have any noticable effect on performance or memory, but delegating the event just makes so much sense, also in regards to keeping a clean maintainable code base.

Also, by delegating the event you can freely add/remove children without worrying about attaching/detaching events.

Example:

var ul = document.getElementsByTagName('ul')[0] // Or similar...
ul.addEventListener('click', function(e) {
    if(e.target.nodeName != 'LI') return;
    var li = e.target
    // map li -> option
});

Of course you’ll need to use attachEvent and srcElement for legacy Internet Explorer support.

Side note: remember that native select boxes are accessible using the keyboard, etc., so you better not rely on just the click handler to create a "progressively enhanced" select box using UL/LI elements.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Hellsing
  • 106,495
  • 44
  • 176
  • 212
0

It would be much slower to attach an event handler to that, instead you can just attach it to the <ul> and get the child element clicked with jQuery, like this

<ul>
    //2000 li's
</ul>

$('#ulParent').on('click', function(event) {
    var clicked=event.target;
});

If you really needed to do it on each element, you could do it with a for loop, but I wouldn't recommend it

var lis = document.getElementById("ulParent").getElementsByTagName("UL");
for(var i=0;i<lis.length;i++){
    $(lis[i]).bind("click"),function(event){
         //do something here
    }
}
scrblnrd3
  • 7,228
  • 9
  • 33
  • 64
  • Don't use `.bind()`. As of jQuery 1.7, the [`.on()`](http://api.jquery.com/on/) method is the preferred method for attaching event handlers to a document. [Source](http://api.jquery.com/bind/). – Richard de Wit Dec 19 '13 at 09:42
0

Use .on() on the parent element. You will only need 1 handler, not more. Explanation

Working example

function bindCustomSelect() {
  $("#ul").on("click", "li", function(){

    updateSelect( $(this).index() );
  });
}

function updateSelect( idx ) {
  var sel = $("#select");
  sel.selectedIndex = idx;
  sel[0].children[idx].selected = "selected";
  sel.change();
}
Community
  • 1
  • 1
EricG
  • 3,788
  • 1
  • 23
  • 34
0

To create select to handle thousands of items, take a look at select2.

It is a jQuery-based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pomaxa
  • 1,740
  • 16
  • 26