2

I have a javascript variable:

var foo='<script type="text/javascript">alert("Hello World");<\/script>'  

The variable is inserted with element.innerHTML=foo; after an event occurs on the page, about 10 seconds after the page is loaded.

Is there a way to execute the 'alert' function right after the insertion?

11
  • Yes, but it's cumbersome as you would have to eval() the script part. jQuery has some functions to do this out of the box - is using it an option? Commented Nov 27, 2011 at 11:30
  • 3
    The way you're inserting that tag, it's not that the code is being set up but not called, it's not being evaluated at all. (If it were, the alert would happen immediately.) There's almost certainly a better way to do what you're trying to do, if you give us more context. Commented Nov 27, 2011 at 11:32
  • Pekka: If your question is "Am I able to use jQuery", then yes, but if it is possible to do it in some other way, that would be better. Commented Nov 27, 2011 at 11:34
  • I am afraid this is the only way I can do it (by inserting the variable), as the "foo" is usually an object. Commented Nov 27, 2011 at 11:36
  • 1
    @Anonymouse: innerHTML is in the process of being standardized, and works better cross-browser than many other things -- just not for this (script injection). Reliability goes down dramatically if you try to create invalid DOM structures with it (setting the innerHTML of a div to "<tr><td>Hi there</td></tr>", for instance), but other than scripting, invalid structures, and some funkiness around form fields in older browsers, it's very reliable. Commented Nov 27, 2011 at 12:49

2 Answers 2

5

If you absolutely, positively have to take JavaScript code that's in a string and execute it, you basically have to use eval or an eval-like mechanism. In some years of JavaScript programming, I've never had to resort to it, and I do suggest that you look at whether there's another way to achieve your actual overall goal.

So here, you'd strip off the script tag stuff and just eval the code, e.g.:

var script = foo.replace(/^<script[^>]*>/, "").replace(/<\/script>$/, "");
eval(script);
// Or window.evalInGlobalScope(script); // -- See below

Obviously you have to be sure you trust the source of the string, since you're executing the code therein.

eval is a slippery beast and plays very odd games with context and scope. If you need something that looks more like what you'd get if you did add a script tag to the page, here's a function that does that cross-browser (from my answer to this other question here on Stack Overflow):

window.evalInGlobalScope = (function() {
    var fname, scr;

    // Get a unique function name
    do {
        fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000);
    }
    while (typeof window[fname] !== 'undefined');

    // Create test script
    scr = "function " + fname + "() { }";

    // Return the first function that works:
    return test(evalInGlobalScope_execScript) ||
           test(evalInGlobalScope_windowEval) ||
           test(evalInGlobalScope_theHardWay) ||
           evalInGlobalScope_fail;

    function test(f) {
        try {
            f(scr);
            if (typeof window[fname] === 'function') {
                return f;
            }
        }
        catch (e) {
            return false;
        }
        finally {
            try { delete window[fname]; } catch (e) { window[fname] = undefined; }
        }
    }
    function evalInGlobalScope_execScript(str) {
        window.execScript(str);
    }
    function evalInGlobalScope_windowEval(str) {
        window.eval(str);
    }
    function evalInGlobalScope_theHardWay(str) {
        var parent, script, d = document;

        parent = d.body || d.documentElement || d.getElementsByTagName('head')[0];
        if (parent) {
            script = d.createElement('script');
            script.appendChild(d.createTextNode(str));
            parent.appendChild(script);
        }
    }
    function evalInGlobalScope_fail() {
        throw "evalInGlobalScope: Unable to determine how to do global eval in this environment";
    }
})();

Live example using the above

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

Comments

0

You don't need to make lots of changes, just one small change.

Right now you have such line of code:

oDiv.innerHTML = foo;

Just change it to those three lines instead:

var oScript = document.createElement("script");
oScript.innerHTML = foo;
oDiv.appendChild(oScript);

And have foo contain only the raw JS, without the <script> and </script> tags.

Live text case.

4 Comments

Setting innerHTML on a script element doesn't work reliably cross-browser. It fails, for instance, in all versions of IE. Hence the various mechanisms used to find the correct evalInGlobalScope function in my answer.
@T.J it works with latest versions of Chrome, Firefox and IE. With IE9 in compatibility mode (hence IE8 as far as I know) failed indeed - know of any other browsers?
@Shadow: IE9, IE8, IE7, IE6 (die! die already!) all fail, but that's fine because they offer execScript. Firefox and some others offer window.eval (as distinct from eval). On just about everything else, creating a text node (rather than setting innerHTML) works. Again, refer to the evalInGlobalScope in my answer. It tests which mechanism is supported by the browser (once). I did a fair bit of research on this a couple of years ago.
OK then, was just hoping for something more simple but guess you're right as usual. :)

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.