tags:

views:

56

answers:

3

Suppose you want to dynamically add to a HTML menu, where the menu HTML will look like-so:

<ul>
<li><a href="#">item-1</a>
<li><a href="#">item-2</a>
</ul>

And each element has a "click" event bound to it by. How does one create this dynamically with jQuery?

What'd I'd like is the equivalent of the following (with hypothetical menu_item array of objects with 'title's):

$('menu').append("<ul>");
for (var index in menu_items) {
    $('menu').append("<li><a href='#'>"+menu_item['title']+"</a>")
             .live("click", function(e) { /* Event Handler */ });
}
$('menu').append("</ul>");

Unfortunately this won't work for two reasons (at least, that I'm aware of):

    • tags can't be added separately like this with jQuery; and
    • the .live() element matches only the most recent element inserted.

    I'd appreciate insight into how one may solve this problem with jQuery. I'd prefer to do this without cluttering up my ID namespace, if that's possible.

    EDIT:

    Two clarifications (in case it's not obvious):

    1. The < ul > doesn't exist to start with.

    2. Information from menu_item is used in the function (i.e. .live('click', function(e) { /* do_something_with ... */ menu_item['info'] } ).

    +3  A: 

    Assuming:

    <ul class="menu">
    <li><a href="#">item-1</a>
    <li><a href="#">item-2</a>
    </ul>
    

    Just do:

    $(function() {
      $("ul.menu a").live("click", function(e) {
        // do stuff
      });
    });
    

    and then elsewhere:

    var ul = $("<ul></ul>");
    for (var index in menu_items) {
      var a = $("<a></a>").text(menu_item["title"]).attr("href", "#");
      $("<li></li>").append(a).appendTo(ul);
    }
    $("...").append(ul);
    
    cletus
    A: 

    .live() is great but for some things the livequery plugin is better. Stealing somewhat from their page you can do

      $('menu') 
        .livequery('click', function(event) { 
            alert('clicked'); 
            return false; 
        });
    

    which will bind to all current and all future menu items.

    stimms
    Im assuming you meant ".menu" ;) - sorry i'm being facetious. Using this method the menu "click" would be triggered anywhere inside that element, the click is required on the li/a elements
    danrichardson
    I am using the same selector as the original question
    stimms
    +1  A: 

    You could use event delegation. So the UL parent has a click event, and then you just look at what got clicked - assuming a div with a class "menu" contains the UL:

    jQuery('div.menu').click(function(e){
        if (jQuery(e.target).is('li')){
            // LI was clicked
            return false;
        }
    }
    

    That way you haven't got a massive bunch of events hanging around, just the one :)

    danrichardson