views:

5837

answers:

4

I have an IE bug that I'm not sure how to fix.

Using jQuery I'm dynamically moving a menu to appear on an element on mouseover.

My code (simplified) looks something like this:

$j = jQuery.noConflict();

$j(document).ready(function()
{
    //do something on the menu clicks
    $j('div.ico').click(function() { alert($j(this).parent().html()); });

    setUpActions('#tableId', '#menuId');
});

//on mouseover set up the actions menu to appear on mouseover
function setUpActions(tableSelector, menuSelector)
{
    $j(tableSelector + ' div.test').mouseover(function()
    {
        //note that append will move the underlying
        //DOM element with all events from it's old
        //parent to the end of this one.
        $j(this).append($j(menuSelector).show());
    });
}

This menu doesn't seem to register events correctly for the menu after it's been moved in IE7, IE8 and IE8-as-IE7 (yeah MS, that's really a 'new rendering engine' in IE8, we all believe you).

It works as expected in everything else.

You can see the behaviour in a basic demo here.

In the demo you can see two examples of the issue:

  1. The image behind the buttons should change on hover (done with a CSS :hover selector). It works on the first mouseover but then persists.
  2. The click event doesn’t fire – however with the dev tools you can manually call it and it is still subscribed.

You can see (2) in IE8's dev tools:

  1. Open page in IE8
  2. Open dev tools
  3. Select "Script" tab and "Console" sub-tab
  4. Type: $j('#testFloat div.ico:first').click() to manually call any subscribed events
  5. There will be an alert on the page

This means that I'm not losing the event subscriptions, they're still there, IE's just not calling them when I click.

Does anyone know why this bug occurs (other than just because of IE's venerable engine)?

Is there a workaround?

Could it be something that I'm doing wrong that just happens to work as expected in everything else?

+1  A: 

I would highly recommend using the Live events instead from the latest jquery.

this way you can bind to elements by css class which have not been created at the beginning but the click binding will be added when the new elements are added:

http://docs.jquery.com/Events/live

Richard
Thanks, nice idea, but I've tried that and it makes no difference. I haven't lost the click event - $j('selector').click() in the javascript command line will fire the event that I expect. The jQuery event subscription has survived the move, it's just that IE doesn't seem to call it. The CSS :hover has the same symptoms.
Keith
do you have a demo page I can look at?
Richard
Yeah - the link's in the question.
Keith
A: 

IE doesn't copy events to items dynamically appended to the DOM.

Try binding your click event after you have added what you need to be bound or use .live()

if you are using clone() remember to pass clone(true) to explicitly request copying of event handlers.

var actionMenu = $j(menuSelector);

//actionMenu is now an Instance of jQuery, not the DOM object
//because jQuery is chainable

actionMenu.hide();

// notice the clone(true)

$j(this).append( actionMenu.clone(true) );

jQuery is chainable, so you can also write this in "jQuery" syntax as:

var clone = $j(menuSelector)
               .clone(true)
               .css('background-color', $j(this).css('background-color') );

$j(this).append(clone);

I don't think you need the show/hide since it happens so fast.

Chad Grant
As you can see from the code sample in the question and the working demo that I'm linking to I'm not using clone(). @richard.grundy suggested using live(), but that makes no difference. I'll try re-binding the events - see if that has any effect.
Keith
Now tested - rebinding the click event doesn't fix it. I can manually call the event - go to my online demo, open the IE8 dev tool's javascript console and call $j('#testFloat div.ico').click() - the action that I've subscribed will then fire.
Keith
My example is simplified code - in the live demo I have a much larger table and a lot more scripting going on. I don't want to clone the element unless I have to. But I've tried this and it has the same issue - the cloned elements can keep the event with live() or re-binding, but that doesn't fix the initial issue of IE not registering the actual click or hover events.
Keith
Thanks for the extended example anyway.
Keith
there's no work around with that, you are appending a jQuery object to the DOM, not the actual DOM object. And you can't append a reference of another DOM object to the DOM. So you need to clone it or insert the HTML manually.When I tested it without live() in IE 8 it works with the code I posted in my answer.
Chad Grant
I think this is on the right track, although cloning creates a whole load of new issues with my larger script. I understood that append() would actually change the DOM, not break out of it. Why does this work fine in everything else?
Keith
+6  A: 

Strangely, although your click event isn't firing in IE, if you change it to either mousedown or mouse up it works as you'd expect although you still have your image hover issue.

$j('div.ico').mouseup(function() { alert($j(this).parent().html()); });

Eifion
Nice workaround - that works! Despite ':hover' being originally an IE extension I think I'll just accept that it doesn't work here. Cheers!
Keith
A: 

Another reason why MSIE should be boycotted

Jimbob
Oh, it's horrible, but we're stuck with it because big companies don't like change. If we excluded IE we just couldn't sell software.
Keith