简体   繁体   中英

Append <li> element to <ul> and add click event for each?

I'd like to add a series of <li> elements to a <ul> , and add a click event to each one, programmatically.

I'm not sure how to do this, at least not in a neat, jQueryish way.

This is my existing code:

<ul id="saved-list"></ul>
<script type="text/javascript">
$.each(all_objects, function() {{
    var list_route = "<li><a href='#saved-route'>" + this.text + "</a></li>";
    $('#saved-list').append(list_route);      
    // add unique id (this.id) to item and click event here?
    // pseudocode - onclick: alert(this.id);
});
$('#saved-list').refresh('listview'); // jquery mobile list refresh
</script>

Please could someone advise how to add a click event to each list item programmatically?

UPDATE: I need to do something slightly different for each list item (let's just say an alert) - apologies for not making this clear.

You're better off using .live() or .delegate() than worrying about creating a .click() handler on every element you create. Something like this:

$('#saved-list').delegate('li', 'click', function () {
    // do stuff on click
});

You only have to bind this click listener once, and it will work for every <li> that is a descendant of the element with ID saved-list .


If you do want to create a separate click handler for every <li> (I don't recommend this though) here's a nice way to do it:

$.each(all_objects, function() {
    var $a = $('<a/>', {
        href: '#saved-route',
        text: this.text
    });

    var $li = $('<li/>', {
        click: function () {
            // do stuff on click
        }
    }).append($a);

    $('#saved-list').append($li);
});

Don't.

Rather than binding a new event handler for each element (which could become quite expensive), bind a single event handler to #saved-list , which is a common ancestor. Event bubbling means that ancestor elements are notified of events on their descendants, so you can handle events there instead of on the originating element.

Something like this...

$.each(all_objects, function() {{
    var list_route = "<li><a href='#saved-route'>" + this.text + "</a></li>";
    $('#saved-list').append(list_route);      
});
$('#saved-list').delegate('li', 'click', function() {
    // do something here each time a descendant li is clicked
});

See delegate

@Matt Ball is pretty close to the answer here, but I will add a little more clearly that you can do different things with the delegate depending on what element was clicked:

<ul id="saved-list"></ul>
<script type="text/javascript">
var $savedList = $("#saved-list");
$.each(all_objects, function() {
    $savedList.append("<li><a href='#saved-route'>" + this.text + "</a></li>");
});
$savedList.delegate("li", "click", function (e) {
    alert($(this).text());
});

$('#saved-list').refresh('listview'); // jquery mobile list refresh

Note that in the delegate this is still referring to the li that was clicked on.

Isn't it enough to add this in (or after) your current loop?

$('#saved-list li').click(function(){ alert('hello'); });

hello phil in jquery you can create dom object without adding them as text to the dom. this will give you a chans to manipulate them before they are added (and after to).

$("<li />")
  .append(
    $("<a />")
     .attr("href" ,"#saved-route")
     .text(this.text))
  .click(function() {
    // your click event
  })
  .appendTo("#saved-list");

You could use the live function, the downfall is that you might need some mechanism to determine exactly which of the li items that have been clicked:

$("#saved-list li").live('click', function() {
    //act on click
});

This is why bind exists.

$.each(all_objects, function(index) {{
    $("#saved-list").append("<li id='item" + index + "'><a href='#saved-route'>" + this.text + "</a></li>");
    $("#saved-list li").bind("click", function() {
        alert("Clicked on " + this.id);
    });
});

Also, this way is very easy to create different clicks for each item:

$("#saved-list li#item1").bind(...)
$("#saved-list li#item2").bind(...)
$("#saved-list li#item3").bind(...)
$.each(all_objects, function() {{
    var list_route = "<li><a href='#saved-route'>" + this.text + "</a></li>";
    var newLi = $(list_route);
    newLi.click( function(){} ).attr("id","foo");
    //if you want the a
    newLi.find("a").click( function(){} ).attr("id","foo");

    $('#saved-list').append(newLi);              
});

The .click function will bind a click handler function to any given element. As the comments in your code mention you can use the ID or other means to select the item after it's been DOM-ized but another way to do this is simply to reference the variable that contains the element you want to bind.

Example:

var li = $('<li />');
li.click(function() { ... });

This is probably somewhat stylistic, but one of the features of jQuery is that it is chainable. This means that jQuery function calls always return a reference to the wrapped set of jQuery itself. Using the chainable aspect, you could re-write the above code like so:

var list = $('#saved-list'); $.each(all_objects, function(i, item) {{
    list.append(
        $('<li />')
            .append(
                $('<a />').text(item.text)
            )
            .click(function() { ... } );
    );
});

Although I don't know what this $('#saved-list').refresh('listview') business is about, the following might be what you're looking for:

var listItemEls = all_objects.map(function () {
    return $('<li id="' + this.id + '"><a href="#saved-route">' + this.text + '</a></li>')
           .click(function (e) {
               // do whatever here
           })
           .get();
});

$('#saved-list').append(listItemEls);

Note that we avoid appending to the DOM until the last minute, because appending is expensive.

As other posters mention, using a delegated click handler is a better approach, generally. That would look something like

var listItemEls = all_objects.map(function () {
    return $('<li id="' + this.id + '"><a href="#saved-route">' + this.text + '</a></li>')
           .get();
});

$('#saved-list').append(listItemEls)
                .delegate("li", "click", function (e) {
                    // do stuff here.
                });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM