简体   繁体   中英

Event doesn't get added in a for-loop

This is the html. If a link is clicked I want to replace the span-element in front of it with some text.

<p><span id="sp1">that1</span> <a href="#" id="update1">Update1</a></p>
<p><span id="sp2">that2</span> <a href="#" id="update2">Update2</a></p>
<p><span id="sp3">that3</span> <a href="#" id="update3">Update3</a></p>
<p><span id="sp4">that4</span> <a href="#" id="update4">Update4</a></p>
<p><span id="sp5">that5</span> <a href="#" id="update5">Update5</a></p>

As you can see, my idea was to give the spans en the anchors identical id's and a number.

In my jquery-code I loop through all the anchor-elements, give them a click-event that causes the span-element in front of it to be replaced.

<script type="text/javascript" >

  $(document).ready(function() {
   var numSpans = $("span").length;
   for (n=0;n<=numSpans;n++) {
     $("a#update" + n).click(function(e){
       $('span#sp' + n).replaceWith('this');
       e.preventDefault();
     });    
   }   
  });

</script>

For some reason this does not work.

What am I doing wrong?

The problem with your original code is that you're creating a closure on the variable n . When the event handler is called, it is called with the value of n at the point of invocation, not the point of declaration. You can see this by adding an alert call:

$(document).ready(function() {
    var numSpans = $("span").length;
    for (n = 1; n <= numSpans; n++) {
        $("a#update" + n).click(function(e) {
            alert(n); //Alerts '6'
            $('span#sp' + n).replaceWith('this');
            e.preventDefault();
        });
    }
})

One way to fix this is to create a closure on the value of n in each iteration, like so:

$(document).ready(function() {
    var numSpans = $("span").length;
    for (n = 1; n <= numSpans; n++) {
        $("a#update" + n).click(
            (function(k) {
                return function(e) {
                    alert(k);
                    $('span#sp' + k).replaceWith('this');
                    e.preventDefault();
                }
            })(n)
        );
    }
})

However, this is messy, and you'd do better to use a more jQuery-y method.


One way to do this would be to remove the id s from your code. Unless you need them for something else, they're not required:

<p><span>that1</span> <a href="#" class="update">Update1</a></p>
<p><span>that2</span> <a href="#" class="update">Update2</a></p>
<p><span>that3</span> <a href="#" class="update">Update3</a></p>
<p><span>that4</span> <a href="#" class="update">Update4</a></p>
<p><span>that5</span> <a href="#" class="update">Update5</a></p>

jQuery:

$(function() {
    $('a.update').live('click', function() {
        $(this).siblings('span').replaceWith("Updated that!");
    });
});

jsFiddle

Don't create functions in a loop. With jQuery, there's no need for an explicit loop at all.

$(function()
{
    $('span[id^=sp]').each(function(n)
    {
        $('#update' + n).click(function(e)
        {
            $('#sp' + n).replaceWith(this);
            return false;
        });
    });
});

Demo: http://jsfiddle.net/mattball/4TVMa/


You can do way better than that, though:

$(function()
{
    $('p > a[id^=update]').live('click', function(e)
    {
        $(this).prev().replaceWith(this);
        return false;
    });
});

Demo: http://jsfiddle.net/mattball/xySGW/

Try this:

$(function(){
    $("a[id^='update']").click(function(){
        var index = this.id.replace(/[^0-9]/g, "");
        $("span#sp" + index).replaceWith(this);
        e.preventDefault();
    });
});

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