views:

107

answers:

1

Code:

$(".box-collapse").live("click",function(){
    if(updating()) return false;
    var b = $(this).parent().parent();
    b.find(".album-div").stop(true,false).slideToggle();
    $.ajax({
        url: addNonce($(this).attr("href")),
        success:function(data){
            c = b.attr("id");
            var resp = $('<div />').html(data);
            var col = $("#"+c+" .box-collapse");
            var ncol = resp.find("#"+c+" .box-collapse");
            col.html(ncol.html());
            col.attr('href',ncol.attr('href'));
            resp.remove();
            clearUpdate(data);
            wait = false;
        }
    });
    return false;
});

This click is being fired twice.

What happens:

  • Click to collapse and it sends a response to save that collapse.
  • Click again to expand and it sends a request to save the expand.
  • Click again to collapse and it is fired twice (leaving it expanded, but collapse is saved).
  • Click again and it fires 4 times.

It only begins multiple firing AFTER the second click. It's baffling me.

If I remove the servicing of the data, it doesn't fire twice. What am I doing wrong on the service? (i.e. I only leave wait = false in success)

The other functions that I use in this call:

function updating(){
    if(!wait) {
        $("#loading").html('Updating...');
        wait = true;
        return false;
    }
    else {
        $("#loading").html('Slow down...');
        return true;
    }
}

function clearUpdate(data){
    var resp = $('<div />').html(data);
    //alert(resp.find("#nonce").val() + " "+$("#nonce").val());
    $("#loading").html(resp.find("#loading").html());
    if(typeof(resp.find("#nonce").val()) == 'undefined'){
        alert(data);
        $("#loading").html("Fatal error. Your session could have ended. <a href='javascript:location.reload()'>Refresh</a>");
        resp.remove();
        return false;
    }
    else if(resp.find("#errorcode_").val() == "refresh"){
        location.reload();
    }
    resp.find(".image-box").each(function(){
        $("#"+$(this).attr("id")).find(".image-count").html($(this).find(".image-count").html());
    });
    $("#nonce").val(resp.find("#nonce").val());
    wait = false;
    resp.remove();
}

The wait flag prevents a request from being sent before the last has been serviced. I do this because I track a nonce and I have to get a new nonce after each request.

Again, if I remove the data servicing, it works fine. But I need to service the data to get the fresh nonce.

Plus, I'm not seeing it crash anywhere. Any help would be great. I'll post any other functions if needed. My full script is pretty large.

Here is the HTML of .box-collapse parent:

    <div class='box image-box album-marker-visible image-box-w-20 image-box-list-0' id='portrait'>
    <h2 class='box-header image-box-header'>
    <input type='checkbox' name='albums[portrait]'>
    <span class='image-box-header-move'>
    <span class='image-album-number'>1</span>. Portrait <input type='hidden' class='image-album-anchor' value='portrait'>
    <input type='hidden' class='image-album-portfolio' value='1'>
    <span class='image-count'>(20)</span>
    <span class='box-mover'>Move to: <a href='images?n=bridals,weddings,engagement,portrait&port=2&nonce=I8FX2BH841' title='Move to Wedding Portfolio'>Wedding Portfolio</a>&nbsp;Move: <a href='images?n=story,portrait,capture,press,concerts&port=1&nonce=I8FX2BH841'>down</a></span></span>
<span class='album-marker'>&nbsp;|&nbsp;<a href='images?ia=3&action=hide&nonce=I8FX2BH841' title='Mark album as hide' class='album-mark-hide album-mark'>hide</a></span>
<a class='box-mover-show box-collapse' href='images?expand=portrait&nonce=I8FX2BH841' title='Expand Portrait'>expand</a></h2> 

There are multiple instances of .box and I didn't show the content after the h2 tag (that's why my div isn't closed).

As requested, this is the step by step process of what SHOULD be happening:

  • I click collapse on a .box-collapse instance. It sends its href.
  • jQuery toggles its slide.
  • On call back I get the new href from the link I just clicked. It should have changed query strings from expand=an_album to collapse=an_album or vise-versa. I also change the state from 'expand' to 'collapse'. I am searching through the response based on the id of the containing .box I just clicked. I am getting the correct response (collapse will change to expand), but jQuery slideToggles twice.
  • In clearUpdate() I update my nonce from the received data. If I don't receive a nonce, I die. I also update the image count for each .box.

I have placed an alert in the success, and on the first click, I get one alert. Click again, I get one alert. Click an THIRD time, I get two alerts. Fourth time, 4 alerts.

I have also done alert($(".box-collapse").length); in my clearUpdate() and the size does not change.

The error lies in the success function and/or clearUpdate. Since I am receiving the exact same HTML as I already have (minus the changes above), is it possible that I am reparsing the javascript and re-binding a click? But this doesn't seem feasible because I should be firing multiple times after the FIRST click. Update I added an alert in the $(document).ready() and I get the alert every time I get a response. So it is re-parsing the javascript and re-binding the click. My immediate fix will be to change it to : $(".box-collapse").die("click").live("click",function()) but I will add a query to disable the javascript header.

Thanks for the help!

A: 

This most likely creates the second click event if data contains the .box-collapse class

var resp = $('<div />').html(data);

Do you really need the class selector? Identifiers should be unique that makes b.html() == $("#"+c+" .box-collapse").html() and b == col[0]

var col = $("#"+c+" .box-collapse");

This is worrying. It means that within resp there is an element with the same id as within b. It is most likely the cause for when switching to click from live that the click event happens twice.

var ncol = resp.find("#"+c+" .box-collapse");

Too little known about the content of .box-collapse or data to understand

col.html(ncol.html());
col.attr('href',ncol.attr('href'));

Now I think I finally understand.

Change the data to contain a JSON object or a simpler HTML structure and it should work like this.

Good example

 data == { "innerText":"expand", "url":"images?expand=portrait&nonce=I8FX2BH841" }

 col.html(data.innerText);
 col.attr('href', data.url);

Bad Example

server response:

data == <span class="innerText">expand</span><span class="url">images?expand=portrait&nonce=I8FX2BH841</span>

var div = $("<div />").html(data);
col.html(div.find(".innerText").html());
col.attr(div.find(".url").html());

and adjust the clearUpdate function

sunn0
Thanks for the comment. You are correct, I want to change the response to JSON, but for beginning testing I just kept the response as HTML. It makes it easier for me to test when I expect a response of what I already have. Good catch with the id, you are right. I never even though about having a non-unique ID when I get a response. I appreciate the input, I will be changing it soon.
Jason