ana
ana

Reputation: 1595

jQuery click function vs inline onclick

I'm trying to reorganize my code and make it more unobstrusive.

Mainly, there is a link for performing an action. If you click on the link, the action is performed via ajax (the ajax code is not on the code here) and the text is replaced by other text, offering the user the ability of undo the action. If the user click the Undo link, ajax restore the previous situation and the text offering the user perform the action it's shown again.

I've made a simpler version of my problem in a single html file (code below). There are two paragraphs. If you click on the link of the first paragraph, which uses inline onclick call, the code works as expected. But if you click on the link of the second paragraph, which uses jQuery onclick function, the Undo link doesn't work, and I can't figure out why.

Any help? Thanks a lot!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <title></title>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>
        $(function() {      
            $(".add2").click(function(){
                var placeId = $(this).parents(".place").attr("id");
                $("#" + placeId + " .add2").remove();
                $("#" + placeId + " .actions").append("<span class=\"added\">Added!</span> <a class=\"undoadd2\" href=\"#\">Undo</a>");
                return false;
            })
            $(".undoadd2").click(function(){
                var placeId = $(this).parents(".place").attr("id");
                $("#" + placeId + " .actions").find("span.added, a.add2").remove();
                $("#" + placeId + " .actions").append("<a class='add2' onclick='copyPlace(\"" + placeId + "\"); return false;' href='#'>Add place</a>");
                return false;
            })
        });

        function addPlace(placeId){
            $("#" + placeId + " .add").remove();
            $("#" + placeId + " .actions").append("<span class=\"added\">Added!</span> <a class=\"undoadd\" href=\"#\" onclick=\"undoAddPlace('" + placeId + "'); return false;\">Undo</a>");
            return false;
        }

        function undoAddPlace(placeId){
            $("#" + placeId + " .actions").find("span.added, a.undoadd").remove();
            $("#" + placeId + " .actions").append("<a class='add' onclick='addPlace(\"" + placeId + "\"); return false;' href='#'>Add place</a>");
            return false;
        }
    </script>

</head>
<body id="home">
    <div class="place" id="3435910">
        <p class="actions"><a href="#" onclick="addPlace('3435910'); return false;" class="add">Add place</a></p>
    </div>

    <div class="place" id="3435912">
        <p class="actions"><a href="#" class="add2">Add place</a></p>
    </div>
</body>
</html>

Upvotes: 10

Views: 67378

Answers (5)

Wolfr
Wolfr

Reputation: 5164

Since you are dynamically adding new items to the DOM, you will have to register the click handler again on the new items.

You can use .live for this.


Update

Since jQuery 1.7, the .on method is preferred way to do this.

Since jQuery 1.9 the .live method has been removed.

Upvotes: 16

ken
ken

Reputation: 3709

Just demonstrating the use of .end() for a more fluid solution:

$(function() {          
    $(".add2").click(function(){
            return $(this).parents(".place")
                .find(".add2")
                    .hide()
                .end()
                .find(".actions")
                    .append("<span class=\"added\">Added!</span> <a class=\"undoadd2\" href=\"#\">Undo</a>");
    });
    $('.undoadd2').live('click', function(){ 
            return $(this).parents(".place")
                .find(".actions")
                    .find("span.added, a.undoadd2")
                        .remove()
                    .end()
                .end()
                .find(".add2")
                    .show();
    });
});

Upvotes: 4

ana
ana

Reputation: 1595

Wow!! Thanks to all of you!

I've read about the live event and final working code is:

$(function() {      
            $(".add2").click(function(){
                var placeId = $(this).parents(".place").attr("id");
                $("#" + placeId + " .add2").hide();
                $("#" + placeId + " .actions").append("<span class=\"added\">Added!</span> <a class=\"undoadd2\" href=\"#\">Undo</a>");
                return false;
            })
            $('.undoadd2').live('click', function(){ 
                var placeId = $(this).parents(".place").attr("id");
                $("#" + placeId + " .actions").find("span.added, a.undoadd2").remove();
                $("#" + placeId + " .add2").show();
                return false;
            });

Previously I used remove() for delete the text that offers to perform the action. I've changed it for hide/show so I don't have to use live also in the first function.

Thanks again!

Upvotes: 2

tvanfosson
tvanfosson

Reputation: 532455

The click handler isn't being picked up when you append the element to the DOM. Try using jQuery to register the click handler by changing the line(s) that look like:

$("#" + placeId + " .actions").append("<span class=\"added\">Added!</span> <a class=\"undoadd\" href=\"#\" onclick=\"undoAddPlace('" + placeId + "'); return false;\">Undo</a>")

To

$("#" + placeId + " .actions").append("<span class=\"added\">Added!</span> <a class=\"undoadd\" href=\"#\" >Undo</a>");
$('#' + placeId + " .actions").find("span:last").find("a").click( function() {
    undoAddPlace( placeId );
    return false;
});

You might be able to do it more simply, but it looks like you could be adding more than one span to the paragraph so I went conservative. You could also probably chain off append, but I thought the reselect made the point clearer.

Upvotes: 1

Daniel A. White
Daniel A. White

Reputation: 190945

Since you are dynamically adding new items to the DOM, you will have to register the click handler again on the new items. jQuery sets the handler when you call $('...').click(...).

Upvotes: 2

Related Questions