views:

231

answers:

3

I am sure this has been discussed repeatedly, but I am stumped. I am using jQuery to make an AJAX call to an ASP.NET Web service which returns some HTML. That part is working fine.

I want to do some calculations on the height of the HTML returned, but when the the call happens for the first time I am getting a height of 0. I know my calculation are just happening before the AJAX call is complete, because on the second attempt it works. If I clear cache then it returns 0 again.

I need to fire an event after the html is rendered. I have tried both global and local events like ajaxComplete.

$.ajax({
    type: "POST",
    url: "Webservices/Service.asmx/HelloWorld",
    data: "{}",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(msg) {
        $("#OverlayContent").html(msg.d);
    }
    complete: function(msg) {
        alert($("#OverlayContent").height());
    } 
});

I appreciate any help.

+4  A: 

Sounds like your height calculation is running before the html is inserted and rendered in the DOM. Make sure to stagger it with a setTimeout call or an interval. For example:

$.ajax({
    type: "POST",
    url: "Webservices/Service.asmx/HelloWorld",
    data: "{}",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(msg) {
        $("#OverlayContent").html(msg.d);
        setTimeout(function(){ getHeight();},100);
    }
});

function getHeight(){
    // If our height is 0, set a new timeout and we'll check again
    if($("#OverlayContent").height() === 0){
        setTimeout(function(){ getHeight() }, 100);
    }
    else{
        alert("The height is: " + $("#OverlayContent").height());
    }
}

You need to poll on the html being inserted into the DOM and rendered.

ajm
This is working, not necessarily the most elegant solutions, definitely better that what I had. The only change I made was to not do the initial timeout, because it will timeout if it is 0 anyway.I can't believe there is no way to fire en event after the DOM has been updated.Thanks a bunch!!!
Dustin Laine
If memory serves me, even something like this would work: setTimeout(getHeight,1);You just need to release to the browser to let it make the DOM changes. I don't think you need the polling inside getHeight--just the setTimeout in success.
Nosredna
In fact, I think I've even had setTimeout(0) work in modern browsers.
Nosredna
This did not work, returned 0 height. I did change the looping timeout to 0 in order to return the height ASAP.
Dustin Laine
Each browser has its own minimum value for the lowest timeout it can run, and that's usually greater than zero. So, setting a timeout of any value below that threshold will in fact drop you back to the browser's lowest value; a zero-millisecond setTimeout call will actually run in greater than zero milliseconds depending on the browser.
ajm
+1  A: 

I may not be understanding your question entirely, but you could try setting the update code in an timeout that runs immediately after the completed event...

//..your other code here

complete:function(m) {
    setTimeout(function() {
        alert($("#OverlayContent").height());
    },1);
}

//...the rest of your code
Hugoware
This is close to the answered question, but the timeout would have to loop to handle different content sizes and loading times. If DOM was not ready after the initial timeout it would not get rerun.
Dustin Laine
+1  A: 

In all likelihood the complete event is firing simultaneously if not before the success event, since complete fires as soon as the AJAX data is finished being received. The success event is fired once it receives return data with the 200 OK status code.

You could use a delay, but personally I think using jQuery's queue() method would be better:

success: function(msg) {
        $("#OverlayContent").html(msg.d).queue(function(){
            alert($("#OverlayContent").height());
            $(this).dequeue();
        })
    }

The dequeue() at the end there is important to restore the normal flow of things.

At that point you just get rid of the complete callback entirely.

Gabriel Hurley
I like this solution better, but it is returning 0 for me.Sorry, but thanks anyway. I will look into the queue a bit more.
Dustin Laine