tags:

views:

35

answers:

2

The first half of this code works perfectly. However the second. Where an items is removed if you click it does not fire.

$(document).ready(function()
{
    $('#contact').click(function() 
    {

        $('#contact_box').remove();

        $('.menu_item_content').prepend('<div class="menu_box" id="contact_box">Contact INFO goes in this box.</div>');

    });

    $('#about').click(function() 
    {

        $('#about_box').remove();

        $('.menu_item_content').prepend('<div class="menu_box" id="about_box">About info goes in this box.</div>');

    });

    $('#twitter').click(function() 
    {

        $('#twitter_box').remove();

        $('.menu_item_content').prepend('<div class="menu_box" id="twitter_box">Twitter</div>');

    });


    //
    //remove single items
    //
    //nothing below this fires for some reason?

    $('#contact_box').click(function() 
    {
        $('#contact_box').remove(); 
    });

    $('#about_box').click(function() 
    {
        $('#about_box').remove();   
    });

    $('#twitter_box').click(function() 
    {
        $('#twitter_box').remove(); 
    });
});

<style>

.menu_item
{
    display:inline;
    font-family:Tahoma;
    font-size:20px;
}
.menu_spacer
{
    display:inline;
    font-family:Tahoma;
    font-size:45px;
}

</style>

<div class="menu">
    <div class="menu_items">
        <div class="menu_item" id="contact">CONTACT</div>
        <div class="menu_spacer">/</div>
        <div class="menu_item" id="about">ABOUT</div>
        <div class="menu_spacer">/</div>
        <div class="menu_item" id="twitter">TWITTER</div>
    </div>

    <div class="menu_item_content">
    </div>
</div>
+2  A: 

The reason this is happening is because the .click() function only binds to the appropriate elements at the time the code is first evaluated (onReady). Since the prepended items didn't yet exist in the DOM, these elements didn't get the click() event bound to them. You COULD put the .click() binding call AFTER the .prepend() function calls, but who knows what other changes you'll want to make to the DOM afterward. Using .live() will make sure that EVERY element which matches the CSS select pattern '#contact_box' will get the function bound to its onClick() event no matter when the element is added to the DOM.

Whew. Hope that was clear. Now consider these changes:

// The below line was changed to a shorthand notation which means the same as $(document).ready(function(){});
$(function()
{
    $('#contact').click(function() 
    {

        $('#contact_box').remove();

        $('.menu_item_content').prepend('<div class="menu_box" id="contact_box">Contact INFO goes in this box.</div>');

    });

    $('#about').click(function() 
    {

        $('#about_box').remove();

        $('.menu_item_content').prepend('<div class="menu_box" id="about_box">About info goes in this box.</div>');

    });

    $('#twitter').click(function() 
    {

        $('#twitter_box').remove();

        $('.menu_item_content').prepend('<div class="menu_box" id="twitter_box">Twitter</div>');

    });


    //
    //remove single items
    //
    //nothing below this fires for some reason?

    // Changes here.
    $('#contact_box').live('click',function() 
    {
        $('#contact_box').remove(); 
    });

    // And changes here.    
    $('#about_box').live('click',function() 
    {
        $('#about_box').remove();   
    });

    // And changes here.
    $('#twitter_box').live('click',function() 
    {
        $('#twitter_box').remove(); 
    });
});

<style>

.menu_item
{
    display:inline;
    font-family:Tahoma;
    font-size:20px;
}
.menu_spacer
{
    display:inline;
    font-family:Tahoma;
    font-size:45px;
}

</style>

<div class="menu">
    <div class="menu_items">
        <div class="menu_item" id="contact">CONTACT</div>
        <div class="menu_spacer">/</div>
        <div class="menu_item" id="about">ABOUT</div>
        <div class="menu_spacer">/</div>
        <div class="menu_item" id="twitter">TWITTER</div>
    </div>

    <div class="menu_item_content">
    </div>
</div>
Michael
Prevents the first half of the code from firing... The menu items.
ian
I see what your saying but how come the first half of the code does work even though the elements don't exists until it creates them?
ian
Which half? Can you show how you made the modifications?
Michael
The part above: // //remove single items // //nothing below this fires for some reason?I change it to this: $('#contact_box').live('click',function(){$('#contact_box').remove();});
ian
The first half of the functions don't need any modification since they are not changing with any of your code. The bottom half, however, is binding the anonymous function you are defining to any element which gets defined with the `id='<something>_box'`.
Michael
So it doesn't bind because when the document loads the element hasn't been created yet?
ian
That's Correct.
Michael
+1  A: 

Since your 'adding' those elements in your first part, you need to use .live() or .delegate() to bind those below events.

example:

$('#contact_box').live('click', function() 
{
    $('#contact_box').remove(); 
});

If you create items on the fly and you miss to directly bind events to them, they don't know about your event handler. That makes total sense, since the execution of that code (which binds the event handler) happens before those elements are beeing created.

.live() and .delegate() kind of "workaround" this behavior. Instead of binding an event handler to the element itself, they are binding an event handler to a parent node. Javascript events will "bubble up" each node (if that isn't prevented), so .live() will "watch" at the document.body for click events after that binding. If it catches an event, it checks the target id and fire your code if it matches.

Now you could say, -boy oh boy, that is like a lot of overhead- and you would be correct. .live() will watch at the top of your document tree, which is the body. That means, any event bound via .live() has to bubble up throw any node that is inbetween. So the clever folks from jQuery said, wait a second, if you know the root node for any new element you are going to create on the fly, it should be enough to watch for bubbling events right there and .delegate() was born. You can tell .delegate() the parent node to observe, no more overhead!

Reference: .live(), .delegate()

jAndy
I tried this but no luck.$("#contact_box").delegate("#contact_box", "click", function(){ $('#contact_box').remove(); });
ian
@ian: can't work, you need to bind `.delegate()` to a **parent** node of `#contact_box`, I've updated my text, read again.
jAndy
@jAndy thanks. got it going with this: $(".menu_item_content").delegate("#contact_box", "click", function() { $('#contact_box').remove(); });
ian