1

My web app dynamically loads sections of its UI with jquery.ajax. The new UI sections come with script though. I'm loading them as such:

Use...

$.ajax({
  url: url,
  dataType: 'html',
  success: function(data, textStatus, XMLHttpRequest) {
      $(target_selector).html( data );
      update_ui_after_load();
  }
});

This almost works. The problem is that the scripts included in the dynamic part of the page run before the new page fragment is inserted into the DOM. But often these scripts want to modify the HTML they're being delivered with. My best hacky solution so far is just to delay the scripts some reasonable amount of time to let the DOM insertion happen, by wrapping them in a setTimeout:

window.setTimeout( function() {
    // process downloaded Fragment
}, 300);

Obviously this is unreliable and hideous. What's a better way?

Leopd
  • 41,333
  • 31
  • 129
  • 167
  • I'm not quite sure if `$(document).ready()` works here, but it's worth a try. If it doesn't you could add something in your ajax success callback function that starts the newly loaded javascript. – Eliasdx Apr 13 '11 at 22:46
  • It still runs too early. That waits for the DOM to be loaded before running, but by the time an ajax call returns, the DOM is generally already loaded. Jquery runs the script before handing the HTML off to the `success` function which merges it into the main page. – Leopd Apr 14 '11 at 15:41

4 Answers4

1

Using

$(function);

will make the function you pass to jQuery to be run after the fragment is inline on the page. I found it in ASP.NET Ajax partial postback and jQuery problem after looking at your question.

Community
  • 1
  • 1
0

Are you familiar with the live() function? Might be what you're looking for here.

http://api.jquery.com/live/

wdm
  • 7,121
  • 1
  • 27
  • 29
  • I can imagine building something with that, but it's not obvious to me what the solution is that involves `live`. Maybe creating a new event type, but that has other complications. – Leopd Apr 14 '11 at 15:42
  • live() allows event handlers to work on content that is dynamically added to a page (i.e. from ajax requests). Wasn't sure if this was part of your problem but thought I'd suggest it just in case. – wdm Apr 14 '11 at 16:02
0

The problem is that the scripts included in the dynamic part of the page run before the new page fragment is inserted into the DOM. But often these scripts want to modify the HTML they're being delivered with.

I'm fairly sure that in that case, the only sensible thing is to place the script after the HTML element.

Everything else would become kludgy quickly - I guess you could implement your own "ready" handler that gets executed after your HTML has been inserted, but that would be a lot of work to implement for no real gain.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • Even if the script is after the ` – Leopd Apr 14 '11 at 15:40
  • @LeoPD I see! That stinks. (although the jQuery manual claims `Returns HTML as plain text; included script tags are evaluated when inserted in the DOM.`... but I assume you have tested this) Maybe using `dataType: "text"` is worth a try - in the hopes that `.html()` executes things in the correct order? – Pekka Apr 14 '11 at 15:47
  • Yeah, that line in the docs is not helpful. Later it says "If html is specified, any embedded JavaScript inside the retrieved data is executed before the HTML is returned as a string." If I get it as text I need to parse it, find any script tags, and run them myself -- I guess with `eval`. That's one way to do it I suppose. – Leopd Apr 14 '11 at 17:05
0

I solved it by making a new simple ready handler system as follows...

var ajaxOnLoad = (function() {
    var ajaxOnLoad = {};
    var onLoadQueue=[];

    ajaxOnLoad.onLoad= function(fn) {
        onLoadQueue.push(fn);
    }           

    ajaxOnLoad.fireOnLoad = function() {
        while( onLoadQueue.length > 0 ) {
            var fn = onLoadQueue.shift();
            fn();
        } 
    } 

    window.ajaxOnLoad = ajaxOnLoad;
    return ajaxOnLoad;
})();

So in the pages which get .ajax() loaded, the scripts are queued to run with

ajaxOnLoad.onLoad( function() {
    // Stuff to do after the page fragment is inserted in the main DOM
});

and in the code which does the insertion, before the update_ui_after_load() call, run

ajaxOnLoad.fireOnLoad();

A more complete solution could parse the pages, find script tags, and queue them up automatically. But since I have complete control of the fragments being inserted, it's easier for me to switch to using ajaxOnLoad.onLoad.

Leopd
  • 41,333
  • 31
  • 129
  • 167