views:

37

answers:

1

Hi,

I have a website which uses jquery and lots of mouseover/mouseout effect. So far I used the .bind() method of jquery but if you have >1000 event handlers, this is slowing down your browser a lot. So, I want to move to use .live or .delegate.

One part of my portal site is a chat area. User can set chat messages which will then be displayed in a simple table. There is a feature that if you move the mouse over a chat message a trash can will appear allowing you to delete the message (if it is by you or you are a moderator).

The trash bin is in the same table cell as the chat message.

The problem: Using .bind() it worked like a charm. This is the old code:

function CreateChatMessageContextMenu(ctrl, messageID, message, sender) {

var a = document.createElement("a");
a.href = "javascript:RemoveChatMessage(" + messageID + ");"
a.id = 'aDeleteChatMessage' + messageID;
a.style.display = 'none';
var img = document.createElement("span");
img.className = "sprite-common messages-image sprite-common-btnDelete";
a.appendChild(img);
ctrl.appendChild(a);


$(ctrl)
    .bind('mouseover', function(event) { $('#aDeleteChatMessage' + messageID).show() })
    .bind('mouseout', function(event) { $('#aDeleteChatMessage' + messageID).hide() });
return;

}

'ctrl' is the reference to a table cell.

Now, using .live() the trashbin also appears but it is flickering a lot and when I move the mouse over the trashbin, it is disappearing or inactive. I have the feeling that more events are thrown or something. It seems like the 'mouseout' is thrown when moving over the trashbin, but the thrashbin is inside the tablecell so mouseout should not be triggered. The new code is as follows.

$(document).ready
{
$('.jDeleteableChatMessage').live('mouseover mouseout', function(event) {
    var linkID = '#aDelete' + event.target.id;
    if (event.type == 'mouseover') {
        $(linkID).show();
    } else {
        $(linkID).hide();
    }
    return false;
});
}

function CreateChatMessageContextMenu(ctrl, messageID, message, sender) {
if (!UserIsModerator && (UserLogin != sender)) return;
ctrl.id = 'ChatMessage' + messageID;
var deleteString = 'Diese Chatnachricht löschen';
if (UserLang == '1') deleteString = 'Delete this chat message';

var a = document.createElement("a");
a.href = "javascript:RemoveChatMessage(" + messageID + ");"
a.id = 'aDeleteChatMessage' + messageID;
a.style.display = 'none';
var img = document.createElement("span");
img.className = "sprite-common messages-image sprite-common-btnDelete";
img.alt = deleteString;
img.title = deleteString;
a.appendChild(img);
ctrl.appendChild(a);

$(ctrl).addClass('jDeleteableChatMessage');

}

I add a class to tell jQuery which chat cell have a trash bin and which don't. I also add an ID to the table cell which is later used to determine the associated trash bin. Yes, that's clumsy data passing to an event method. And, naturally, there is the document.ready function which initialises the .live() method.

So, where is my mistake?

+1  A: 

I'd use the jQuery events to prevent your flicker, they provide a bit more intelligent firing here: mouseenter and mouseleave. Keep in mind that hover is also supported on .live() now as well.

You can use hover (mouseenter/mouseleave) like this:

$('.jDeleteableChatMessage').live('hover', function(event) {
  $('#aDelete' + this.id).toggle();
  return false;
});
Nick Craver
It works! But the trick was replacing "event.target.id" with "this.id". If I substitute this in my code it also works. Still, your code is more elegant and I'll take it :)
Sparhawk
@Kay - Welcome to SO, and thanks for asking a **good** well though-out/explained question +1
Nick Craver