tags:

views:

54

answers:

2

Which of the following is better?
1) Create the element on each loop

$(obj).children('option').each(function(){
  var item = $('<div />')
    .html($(this).text())
    .append(plus)
    .addClass('ui-widget-content ui-state-default')
    .hover(
      function(){$(this).addClass('ui-state-hover')}, 
      function(){$(this).removeClass('ui-state-hover');}
    );
    $(list).append(item);
});


2)Create the element, only change it's html on each loop
Note: This does not work, It requires .clone() as below.

var item = $('<div />')
  .addClass('ui-widget-content ui-state-default')
  .hover(
    function(){$(this).addClass('ui-state-hover')}, 
    function(){$(this).removeClass('ui-state-hover');});

$(obj).children('option').each(function(){
  $(item).html($(this).text()).append(plus);  
  $(list).append(item);
});


Update:
So, after reviewing all the answers/comments here is the final function. Any more improvements?

function create_list(obj) {
  var list = $('<div />')
    .attr('id','keyword_unselect').addClass('ui-widget')
    .delegate("div", "mouseenter mouseleave", function() {
      $(this).toggleClass('ui-state-hover');
    });

  var plus = $('<div />').addClass('ui-icon-plus');

  var item = $('<div />')
    .append(plus)
    .addClass('ui-widget-content ui-state-default');

  $(obj).children('option').each(function(){    
    item.clone(true)
      .prepend(this.text)
      .appendTo(list);
  });
  return list;
};
+1  A: 

The first in this case, though the second would be better, but it currently has a different effect (the element moves each time).

Create it once and .clone() it for appending, like this:

 var item = $('<div />', { 'class': 'ui-widget-content ui-state-default' })
                  .hover(function(){$(this).addClass('ui-state-hover')}, 
                         function(){$(this).removeClass('ui-state-hover');});

$(obj).children('option').each(function(){
  $(list).append(item.clone(true).html(this.text).append(plus));
});

You can give it a try here.

I'm using the .text property of the <option> directly to save a few CPU cycles as well, just reverse this if you need to encode the content for some reason.


Or a bit more efficient version using .delegate() to only bind those mouseneter and mouseleave events once:

$(list).delegate("div", "mouseenter mouseleave", function() {
    $(this).toggleClass('ui-state-hover');
});

var item = $('<div />', { 'class': 'ui-widget-content ui-state-default' });    
$(obj).children('option').each(function(){
  $(list).append(item.clone().html(this.text).append(plus));
});

You can give it a try here.

Nick Craver
I have noticed that you are using toggleClass. This does not seem to have an effect in this context?
Hailwood
@Hailwood - It'll toggle the class on and off when hovering (`mouseneter`/`mouseleave`), so if it initially doesn't have he class (since we're guaranteed of that here), it'll have the same effect as your original code.
Nick Craver
any idea why I am not seeing they effect then? (not even an error message)
Hailwood
@Hailwood - It binds the handler twice in that situation I'll look into it a bit later, for now I posted an even more efficient version that doesn't copy those event handlers, just creating a pair one for the entire list.
Nick Craver
@Nick - Adding a switch to your `toggleClass` corrects it. `,e.type === 'mouseenter'`. Don't know why.
patrick dw
@Nick - I did notice that the `mouseenter` and `mouseleave` events are firing twice, so I guess that's reversing the `toggleClass` if you don't have the switch.
patrick dw
@patrick - Yeah I'm not sure why that's happening, will take a look after setting up this web server I'm working on atm.
Nick Craver
@Nick - Just to add another note, `hover()` seems to bind `mouseenter mouseleave mouseover mouseout`. So if you `.unbind('mouseover mouseout')` it fixes the toggle without using the switch, since you no longer have the same handler double-firing. I'll let you take it from there. :o)
patrick dw
@patrick - Ah you're right that internal mapping is what's doing it, the one added to resolve `.live()` is creating a bug here. Nice catch!
Nick Craver
+1  A: 

By virtue of the fact that you're doing less in the second version, I'd say it's safe to say that the second one will be more efficient.

Although I think you're going to need to .clone() the item in order to ensure that you're working with a new copy.

Also, you could add the plus to the original, then .prepend() the text.

Finally, you can use .appendTo() instead of .append() when appending it to list.

var item = $('<div />')
  .addClass('ui-widget-content ui-state-default')
  .append(plus)
  .hover(
    function(){$(this).addClass('ui-state-hover')}, 
    function(){$(this).removeClass('ui-state-hover');});

$(obj).children('option').each(function(){
  item.clone(true)
      .prepend( $.text([this]) )
      .appendTo(list);  
});
patrick dw
`$.text(this)` will blow up ;) `jQuery.text` is a sizzle method which expects an array.
Nick Craver
@Nick - Yes, I forgot the array. Thanks for the heads up! :o)
patrick dw
what is `$.text([this])` compared to `$(this).text()`?
Hailwood
@Hailwood - It will give the same result, but is a little faster because you don't need to create another jQuery object with `$(this)`.
patrick dw