0

I have 2 files, the first file has some HTML and a portion of JS. The second file is the main file, and it loads the first file thru' XmlHttpRequest.

The first file is like this:

<div>
  My HTML contents
</div>

<script id="my_js_block">
function my_function() {
  alert(9);
}
</script>

The second file is like this:

<div id="div_ajax_content">
  &nbsp;
</div>

<script>
function load_ajax_content() { 
  //synchronously with XmlHttpRequest(...,...,false);
  //...load and throw the first file into 'div_ajax_content'
}

load_ajax_content();
my_function();  <-- fails here
</script>

How to solve this matter?

2
  • i've just edited the question. Commented Nov 16, 2011 at 0:49
  • I guess you can't call the function, because an AJAX - call is asynchronous. That means you have to wait for the call to finish before calling my_function() Commented Nov 16, 2011 at 0:51

3 Answers 3

4

Ajax is asynchronous. Your code attempts to call my_function() before the XMLHttpRequest has completed. Do this instead:

<script>
function load_ajax_content() {
    //...load and throw the first file into 'div_ajax_content'
    // then,
    my_function();
}

load_ajax_content();
</script>

Okay, so now your ajax call is synchronous. You can parse the returned HTML for <script> tags, and handle them separately, but it's not pretty:

function load_ajax_content() {
    //...load and throw the first file into 'div_ajax_content'
    // then grab the script nodes one-by-one
    var scriptElts = document.getElementById('div_ajax_content').getElementsByTagName('script'),
        scriptElt,
        propName; // http://www.quirksmode.org/dom/w3c_html.html#t07

    if (scriptElts.length) {
        propName = scriptElts[0].textContent ? 'textContent' : 'innerText';
    }

    for (var i=0; i<scriptElts.length; i++) {
        scriptElt = document.createElement('script');
        scriptElt[propName] = scriptElts[i][propName];
        document.body.appendChild(scriptElt);
    }

    // finally,
    my_function();
}

...or you could just use a library like jQuery, which automagically handles this exact problem (and many others!) for you.

Sign up to request clarification or add additional context in comments.

5 Comments

i've just amended the question. it loads synchronously
@PaulDinh Still, in your given example, you are calling my_function()right after load_ajax_content(), while the request is still "on the way". Try moving the my_function() call to the end of your load_ajax_content - function as Matt suggested and it should work.
@PaulDinh Ah, I see, sorry. Learned something again today trough that example :)
@MattBall but adding elements from script is such a pain, i decide to use eval()
@PaulDinh But please, don't use it unless you can make absolutely sure that it's impossible for a user to input something that gets passed to eval()
3

Adding a script via innerHTML does NOT run the script. Therefore your function is not being defined, hence the failure.

Instead, I suggest loading HTML and JS separately, and either appending the JS using DOM methods to put the <script> tag on the page, or eval() to execute the returned file contents.

5 Comments

eval() is one of the solution, but i don't know if there is a more pure way
eval() is okay to use here because JS is an interpreted language (you don't compile it - browsers do to boost performance, but it is not required), and because it is a one-time thing. If you were to use eval in a big loop, that'd be bad, but for single-use bits like that it's fine.
will it fail if i call eval("function my_func(){}") twice? (may be error like 'function redefinition'?)
I don't think so. Although, I always declare functions with my_func = function() {...};
your way to declare the function as variable is great, it makes these functions become global when evaluated by eval(), instead of being 'local' in the context where 'eval()' is called. tks :)
0

Following Kolink I found a pretty funny method but it works!

load_ajax_contents();
eval(document.getElementById("my_js_block").innerHTML);
my_function();

However, in order to make those functions evaluated by 'eval()' global, all the functions in the first file must be declared as variables, like this:

//this works!
my_function = function() {
  alert(9);
}

and not:

//this makes the function nested in the context where eval() is called
function my_function() { 
  alert(9);
}

and also not:

//this makes the variable local to the context where eval() is called
var my_function = function() {
  alert(9);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.