Executing embedded JavaScript after Ajax-call

A nasty problem jumped up and bit me in the ass a few days ago at work. I was making a widget of a piece of code formerly part of the web page now hosting the widget. The widget code consisted of some HTML and a couple of embedded JavaScript tags. The widget needed to be loaded into a div the hosting web page with an Ajax-call, after which the embedded JavaScript needed to be executed. Something like this (I’m using YUI3 here):

Y.io("/foo/bar/some_widget", {
  method: 'GET',
  on: {
    complete: function(id, respdata) {
      thediv.innerHTML = respdata.responseText;
      initWidget(); // this function is embedded in the responseText
                    // and doesn't get evaluated. I.e. it doesn't exist.
    },
    failure: function(id, respdata) {
      alert('Feed failed to load!');
    }
  }
});

If a search engine sent you here, you probably know that this doesn’t work. JavaScript embedded in a piece of HTML code loaded with Ajax and injected in a web page doesn’t get evaluated. If you’re wondering why, you’re in the wrong place. If you want to know how to make it execute, read on.

The only solution I could think of right away was to put the JavaScript code in the hosting web page, thus evaluating it before the widget got loaded/deployed, then calling the initWidget() function when the widget loaded. IMHO this is kind of ugly since the code belonging to the widget would be scattered over multiple locations. Encapsulation is a Good Thing, so I wanted to keep the JavaScript code embedded in the HTML file. Another reason for keeping the HTML and JS in the same file was that they both were generated by the same Ruby on Rails code, to some extent.

In other words, I was fresh out of ideas. I googled around for a solution and found a guy whose solution was to make a “real” Ajax call, returning a piece of XML code consisting of two elements, one for the HTML and one for the JavaScript code. The HTML code would then be injected into the web page and the JavaScript code would be evaluated, voilà. Instead of seeing a good solution, I saw a fair amount of re-coding (I’ll leave out the reasons).

However, his idea of “reading” the JavaScript in the Ajax result and evaluating it got me thinking. Why can’t I do just the same with my existing piece of HTML/JavaScript code? So by using for example the Prototype JS library (which I’m not a fan of, btw), I was able to do this:

Y.io("/foo/bar/some_widget", {
  method: 'GET',
  on: {
    complete: function(id, respdata) {
      thediv.innerHTML = respdata.responseText;

      scripts = $$('#widget script'); // look up the script tags in the widget HTML
      for(var i = 0; i < scripts.length; i++) {
        eval(scripts[i].innerHTML);   // for each script tag, evaluate its contents
      }

      initWidget(); // this function has now been evaluated, will work!
    },
    failure: function(id, respdata) {
      alert('Feed failed to load!');
    }
  }
});

This is essentially the same solution as the above guy proposed, only using the original HTML code instead of wrapping it in XML.

Disclaimer: This is a simplified version of what’s really going on and merely shows the general idea. In my real life version, there’s no initWidget() function, instead the embedded JavaScript (in the following replaced by the alert) is wrapped in a call to (here using YUI2):

YAHOO.util.Event.onDOMReady(function() { alert('execute me!'); });

This actually executes the code when the HTML has been properly injected into the hosting web page, eliminating the need to explicitly call an initializing function after the eval. However, the above code might still work.

Advertisements

5 Comments

Filed under Geek speak, JavaScript

5 responses to “Executing embedded JavaScript after Ajax-call

  1. Johan

    voila is, i believe, the right spelling 🙂
    Fritt fram att deleta den här posten 🙂

  2. Chema

    Great job. Very useful. Thank you very much.

  3. Pingback: 学习使用YUI3 | 勇者无疆

  4. Pifa

    Nope Johan, “voilà” is the right spelling (i’m French).

    However, being not a specialist in js, I do not really get the point of what you did. Though you seemed to have exactly the same problem as I have: I load some content with AJAX, in which there are some js functions (depending on php values), and this js script cannot be executed by the browser.

    Could anyone help me about that?

    Thx a lot!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s