Search code examples
javascriptdomprototypejs

Problem accessing the content of a div when that content came from an Ajax call


Here's a very simple Prototype example.

All it does is, on window load, an ajax call which sticks some html into a div.

<html>
    <head>
        <script type="text/javascript" src="scriptaculous/lib/prototype.js"></script>
        <script type="text/javascript">
            Event.observe(window, 'load', function(){
                new Ajax.Request('get-table.php', {
                    method:  'get',
                    onSuccess:  function(response){
                        $('content').innerHTML = response.responseText;
                        //At this call, the div has HTML in it
                        click1();
                    },
                    onFailure:  function(){
                        alert('Fail!');
                    }
                });
                //At this call, the div is empty
                click1();
            });

            function click1(){if($('content').innerHTML){alert('Found content');}else{alert('Empty div');}}
        </script>
    </head>
    <body><div id="content"></div></body>
</html>

The thing that's confusing is the context in which Prototype understands that the div actually has stuff in it.

If you look at the onSuccess part of the ajax call, you'll see that at that point $('content').innerHTML has stuff in it.

However when I check $('content').innerHTML right after the ajax call, it appears to be empty.

This has to be some fundamental misunderstanding on my part. Anyone care to explain it to me?


Edit
I just want to clarify something. I realize that the Ajax call is asynchronous.

Here's the actual order that things are being executed and why it's confusing to me:

  1. The page loads.
  2. The Ajax request to get-table.php is made.
  3. The call to click1() INSIDE onSuccess happens. I see an alert that the div has content.
  4. The call to click1() AFTER the Ajax call happens. I see an alert that the div is empty.

So it's like the code is executing in the order it's written but the DOM is not updating in the same order.


Edit 2 So the short answer is that putting the code in onSuccess is the correct place.

Another case to consider is the one where you do an Ajax call and then do another Ajax call from the onSuccess of the first call like this:

new Ajax.Request('foo.php',{
  method:  'get',
  onSuccess:  function(response){
    doAnotherAjaxCall();
  }
});

function doAnotherAjaxCall(){
  new Ajax.Request('foo.php',{
    method:  'get',
    onSuccess:  function(response){
      //Anything that needs to happen AFTER the call to doAnotherAjaxCall() above
      //needs to happen here!
    }
  });
}

Solution

  • The first letter of AJAX stands for "asynchronous". This means that the AJAX call is performed in the background, i.e. the AJAX request call immediately returns. This means that the code immediately after it is normally actually executed before the onSuccess handler gets called (and before the AJAX request has even finished).

    Taking into account your edited question: in some browsers (e.g. Firefox), alert boxes are not as modal as you might think. Asynchronous code may pop up an alert box even if another one is already open. In that case, the newer alert box (the one from the asynchronous code) gets displayed on top of the older one. This creates the illusion that the asynchronous code got executed first.