Executing <script> injected by innerHTML after AJAX call - javascript

There's a div called "Content":
<div id="content"></div>
It should be filled with data from a PHP file, by AJAX, including a <script> tag. However, the script inside this tag is not being executed.
<div id="content"><!-- After AJAX loads the stuff that goes here -->
<script type="text/javascript">
//code
</script>
<!-- More stuff that DOES work here -->
</div>

I used this code, it is working fine
var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
eval(arr[n].innerHTML)//run script inside div

JavaScript inserted as DOM text will not execute. However, you can use the dynamic script pattern to accomplish your goal. The basic idea is to move the script that you want to execute into an external file and create a script tag when you get your Ajax response. You then set the src attribute of your script tag and voila, it loads and executes the external script.
This other StackOverflow post may also be helpful to you: Can scripts be inserted with innerHTML?.

If you load a script block within your div via Ajax like this:
<div id="content">
<script type="text/javascript">
function myFunction() {
//do something
}
myFunction();
</script>
</div>
... it simply updates the DOM of your page, myFunction() does not necessarily get called.
You can use an Ajax callback method such as the one in jQuery's ajax() method to define what to execute when the request finishes.
What you are doing is different from loading a page with JavaScript included in it from the get-go (which does get executed).
An example of how to used the success callback and error callback after fetching some content:
$.ajax({
type: 'GET',
url: 'response.php',
timeout: 2000,
success: function(data) {
$("#content").html(data);
myFunction();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("error retrieving content");
}
Another quick and dirty way is to use eval() to execute any script code that you've inserted as DOM text if you don't want to use jQuery or other library.

Here is the script that will evaluates all script tags in the text.
function evalJSFromHtml(html) {
var newElement = document.createElement('div');
newElement.innerHTML = html;
var scripts = newElement.getElementsByTagName("script");
for (var i = 0; i < scripts.length; ++i) {
var script = scripts[i];
eval(script.innerHTML);
}
}
Just call this function after you receive your HTML from server. Be warned: using eval can be dangerous.
Demo:
http://plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview

This 'just works' for me using jQuery, provided you don't try to append a subset the XHR-returned HTML to the document. (See this bug report showing the problem with jQuery.)
Here is an example showing it working:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>test_1.4</title>
<script type="text/javascript" charset="utf-8" src="jquery.1.4.2.js"></script>
<script type="text/javascript" charset="utf-8">
var snippet = "<div><span id='a'>JS did not run<\/span><script type='text/javascript'>" +
"$('#a').html('Hooray! JS ran!');" +
"<\/script><\/div>";
$(function(){
$('#replaceable').replaceWith($(snippet));
});
</script>
</head>
<body>
<div id="replaceable">I'm going away.</div>
</body>
</html>
Here is the equivalent of the above: http://jsfiddle.net/2CTLH/

Here is a function you can use to parse AJAX responses, especially if you use minifiedjs and want it to execute the returned Javascript or just want to parse the scripts without adding them to the DOM, it handles exception errors as well. I used this code in php4sack library and it is useful outside of the library.
function parseScript(_source) {
var source = _source;
var scripts = new Array();
// Strip out tags
while(source.toLowerCase().indexOf("<script") > -1 || source.toLowerCase().indexOf("</script") > -1) {
var s = source.toLowerCase().indexOf("<script");
var s_e = source.indexOf(">", s);
var e = source.toLowerCase().indexOf("</script", s);
var e_e = source.indexOf(">", e);
// Add to scripts array
scripts.push(source.substring(s_e+1, e));
// Strip from source
source = source.substring(0, s) + source.substring(e_e+1);
}
// Loop through every script collected and eval it
for(var i=0; i<scripts.length; i++) {
try {
if (scripts[i] != '')
{
try { //IE
execScript(scripts[i]);
}
catch(ex) //Firefox
{
window.eval(scripts[i]);
}
}
}
catch(e) {
// do what you want here when a script fails
// window.alert('Script failed to run - '+scripts[i]);
if (e instanceof SyntaxError) console.log (e.message+' - '+scripts[i]);
}
}
// Return the cleaned source
return source;
}

If you are injecting something that needs the script tag, you may get an uncaught syntax error and say illegal token. To avoid this, be sure to escape the forward slashes in your closing script tag(s). ie;
var output += '<\/script>';
Same goes for any closing tags, such as a form tag.

This worked for me by calling eval on each script content from ajax .done :
$.ajax({}).done(function (data) {
$('div#content script').each(function (index, element) { eval(element.innerHTML);
})
Note: I didn't write parameters to $.ajax which you have to adjust
according to your ajax.

I had a similiar post here, addEventListener load on ajax load WITHOUT jquery
How I solved it was to insert calls to functions within my stateChange function. The page I had setup was 3 buttons that would load 3 different pages into the contentArea. Because I had to know which button was being pressed to load page 1, 2 or 3, I could easily use if/else statements to determine which page is being loaded and then which function to run. What I was trying to do was register different button listeners that would only work when the specific page was loaded because of element IDs..
so...
if (page1 is being loaded, pageload = 1)
run function registerListeners1
then the same for page 2 or 3.

My conclusion is HTML doesn't allows NESTED SCRIPT tags. If you are using javascript for injecting HTML code that include script tags inside is not going to work because the javascript goes in a script tag too. You can test it with the next code and you will be that it's not going to work. The use case is you are calling a service with AJAX or similar, you are getting HTML and you want to inject it in the HTML DOM straight forward. If the injected HTML code has inside SCRIPT tags is not going to work.
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body></body><script>document.getElementsByTagName("body")[0].innerHTML = "<script>console.log('hi there')</script>\n<div>hello world</div>\n"</script></html>

you can put your script inside an iframe using the srcdoc attribute
example:
<iframe frameborder="0" srcdoc="
<script type='text/javascript'>
func();
</script>
</iframe>

Another thing to do is to load the page with a script such as:
<div id="content" onmouseover='myFunction();$(this).prop( 'onmouseover', null );'>
<script type="text/javascript">
function myFunction() {
//do something
}
myFunction();
</script>
</div>
This will load the page, then run the script and remove the event handler when the function has been run. This will not run immediately after an ajax load, but if you are waiting for the user to enter the div element, this will work just fine.
PS. Requires Jquery

Related

How to delay script tag until other script tag has run

I've been experimenting with metaprogramming in webpages, and need to delay a script tag from running until just after another script tag has been run. However, the script tag needs to be loaded first or both of them will fail.
Shortened and more readable version of what I'm trying to do:
<script defer>
w=function(){
<stuff that gives a parser error until modified by the next script tag>
}
</script>
<script>
<stuff that changes the previous script tag and any other script tags that ever will be added via the DOM
so it doesn't give a parser error>
</script>
<button onclick='w()'></button>
This would work perfectly well, except that the button's onclick attribute fails because the button was loaded before the first script tag was run.
Thanks in advance!
(EDIT: I linked a pastebin to show the full version of my code, it might clear things up a bit since it seems my summed-up version wasn't very good.
As suggested by #meagar in the comments, if you don't mind changing the type property of your "not actually javascript" script blocks you can do something like this:
<script type='derpscript'>
var derp;
var w=function(){alert('hello')};
derp||=5;
console.log(derp);
</script>
<script>
function compileDerps() {
// find all derpscript script tags
var x = document.querySelectorAll('script[type=derpscript]');
for(var i=0;i<x.length;i++){
meta=x[i].text
while(true){
pastmeta=meta;
console.log(exc=regex.exec(meta))
if(exc){
meta=meta.replace(regex,exc[1]+'='+exc[1]+'||');
}
if(pastmeta==meta){break;}
}
// make a new javascript script tag to hold the compiled derp
var s = document.createElement('script');
s.text = meta;
document.body.appendChild(s);
// delete the derpscript tag
x[i].parentNode.removeChild(x[i]);
}
}
//stuff that changes the previous script tag and any other script tags that ever will be added via the DOM
var regex=/([a-zA-Z$_][a-zA-Z$_1-9]*)(\|\|\=)/;
var meta;
var pastmeta='';
var exc='';
compileDerps();
</script>
<button onclick='w()'>THIS IS W</button>

What is read first HTML or JavaScript?

from an issue I am experiencing I understand how it works, but I can't find any formal reference that helps me to clarify the behaviour.
<head>
<title>Chapter 7: Example 7</title>
<script type="text/javascript">
var formWeek = document.form1;
var weekDays = new Array();
weekDays = formWeek.theDay.options;
function btnRemoveWed_onclick()
{
console.log("In btnRemoveWed_onclick");
}
</script>
</head>
<body>
<form action="" name="form1">
<select name="theDay" size="5">
<option value="0" selected="selected"></option>
With this code I receive an error on line "weekDays = formWeek.theDay.options;" because "theDay" is not defined. So I believe that while the JS code is executed the browser has not parsed and loaded the DOM (hence it doesn't know about form1).
If I move the variable definition inside the function, everything works fine.
function btnRemoveWed_onclick()
{
console.log("In btnRemoveWed_onclick");
var formWeek = document.form1;
var weekDays = new Array();
weekDays = formWeek.theDay.options;
}
At function execution the browser knows about form1 (load all the HTML code).
So... from the code the behaviour is clear but still it has not 'clicked' on my mind how it works.
I thought that the link below was a good reference to understand the behaviour.
Where should I put <script> tags in HTML markup?
Can you point me to some good reading that explains HTML-JS loading?
For what i know, javascript is loaded in line with HTML. So if you have an element <foo> and then a script that uses <foo> after that, it works. Turn them around, and the script is loaded first, after that the foo element. This way your script cannot find the element.
Change your javascript to:
function init()
{
var formWeek = document.form1;
var weekDays = new Array();
weekDays = formWeek.theDay.options;
function btnRemoveWed_onclick()
{
console.log("In btnRemoveWed_onclick");
}
}
document.addEventListener('DOMContentLoaded', init, false);
this way you make sure the javascript is loaded when the DOM is ready.
When you have an inline script tag in HTML, it blocks the parsing of HTML and it is executed immediately. Anything written after it has not been parsed yet.
It's common practice to put script tags at the end of the body tag, because at that point the DOM has been parsed and JS can safely execute.
As far as the error you pointed out is concerned, you can wait for the browser to finish loading the page by using something like window.onload. Notice lower in the documentation, in the Notes section
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links and sub-frames have finished loading.
This means by the time the code is run, your HTML has been parsed and put into the DOM. Your script tag, then, will be:
<script type="text/javascript">
window.onload = function() {
var formWeek = document.form1;
var weekDays = new Array();
weekDays = formWeek.theDay.options;
}
function btnRemoveWed_onclick()
{
console.log("In btnRemoveWed_onclick");
}
</script>

Write a js script in a div

I am trying to get a script from another website using jQuery then document.write it
here is my code
var url = "https://code.jquery.com/jquery-1.10.2.js";
var dam = $.getScript(url);
document.write(dam);
But this doesn't work!!
all what I get on the page is [object Object]
Can this be achieved without XHR?
jsfiddle
Don't use document.write, it does not do what you think it does. What it does not do is write some data at the end of the document. What it does instead, is pipe data into the current write stream. And if there is no write stream, it will make a new one, resetting the document's content. So calling document.write(dam) means you just wiped your document. document.write is a low level JS function from an earlier era of JavaScript, don't use it.
Instead, you want to use modern DOM manipulation functions, so in jQuery, that's stuff like:
$(document.head).append($("<script>").attr("src", url));
where
$("<script>")
builds a new script element,
$(...).attr("src", url)
sets the "src" attribute to what you need it to be, and:
$(document.head).append(...)
or
$(document.body).append(...)
to get the script loaded into your document. If it's a plain script with src attribute, it can basically go anywhere, and if it's a script with text content that should run, you can only make that happen through document.head.
Although if it's just a script you need to load in and run, you can use getScript, but then you don't need to do anything else, it's just:
var url = "https://code.jquery.com/jquery-1.10.2.js";
jQuery.getScript(url);
Done, jQuery will load the script and execute it. Nothing gets returned.
Of course, the code you're showing is loading jQuery, using jQuery, so that's kind of super-odd. If you just want to load jQuery on your page, obviously you just use HTML:
<!doctype html>
<html>
<head>
...
</head>
<body>
...
<script src="http://https://code.jquery.com/jquery-1.10.2.js"></script>
</body>
</html>
with the script load at the end so the script load doesn't block your page. And then finally: why on earth are we loading jQuery version 1.x instead of 2.x? (if you need to support IE8: that's not even supported by Microsoft anymore, so you probably don't need to).
And finally, if we don't want to load the script, but we really just want its content, as plain text, there's only a million answers on Stackoverflow already that tell you how to do that. With jQuery, that's:
$.get("http://https://code.jquery.com/jquery-1.10.2.js", function(data) {
$(document.body).append($("div").text(data));
});
But you knew that already because that's been asked countless times on Stackoverflow and you remembered to search the site as per the how to ask instructions before asking your question, right?
executing the script on the page is not my goal!. I want to get the
script content and put it a div (USING JAVASCRIPT - NO XHR) , is that
possible ?
Try utilizing an <iframe> element
<div>
<iframe width="500" height="250" src="https://code.jquery.com/jquery-1.10.2.js">
</iframe>
</div>
jsfiddle http://jsfiddle.net/snygv469/3/
Make it easier... use my fiddle
http://jsfiddle.net/wwwfzya7/1/
I used javascript to create an HTML element
var url = "https://code.jquery.com/jquery-1.10.2.js";
var script = document.createElement("SCRIPT"); //creates: <script></script>
script.src = url; //creates: <script src="long_jquery_url.js"></script>
document.body.appendChild(script); //adds the javascript-object/html-element to the page.!!!
Use this way, it can fix your problems.
$.get( "https://code.jquery.com/jquery-1.10.2.js", function( data ) {
alert(data);
});
You can try adding
<script src="http://code.jquery.com/jquery-1.8.3.min.js" ></script>
Then an AJAX call, but it pulls data from CACHE. It looks like an AJAX but when <script> is added file goes in cache, then read from cache in the ajax. In cases where it is not stored in cache read it using normal AJAX.
jQuery.cachedScript = function(url, options) {
// Allow user to set any option except for dataType, cache, and url
options = $.extend(options || {}, {
dataType: "text",
cache: true,
url: url
});
// Use $.ajax() since it is more flexible than $.getScript
// Return the jqXHR object so we can chain callbacks
return jQuery.ajax(options);
};
$(document).on('ready', function() {
// Usage
$.cachedScript("http://code.jquery.com/jquery-1.8.3.min.js").done(function(script, textStatus) {
console.log(script);
});
});
Normal Solution
If you are ready to use AJAX look at this fiddle
How to fetch content of remote file and paste it on your document and execute that js code
I guess you want to get content written on remote file and want to write that content in your HTML. to do this you can use load() function.
To do this follow the following steps:
1. Create a file index.html Write the following code in it:
<pre id="remote_script"></pre>
<script>
$(document).ready(function() {
//var url = "https://code.jquery.com/jquery-1.10.2.js";
var url = "remote_script.html";/* For testing*/
$('#remote_script').load(url,function(){
eval($('#remote_script').text()); /* to execute the code pasted in #remote_script*/
});
});
</script>
2. Create another file remote_script.html for testing write alert('a'); in it without any <script> tag and run the above code.

JavaScript not executing on Ajax loaded content (no jQuery)

I am having an issue where I am loading ajax HTML content into an element on my page using JavaScript, and trying to execute JavaScript within the loaded content, which is not working.
I am not (and cannot) use jQuery on this project.
The JavaScript I am using to load the ajax content look like:
var loadedobjects = "";
var rootDomain = "http://" + window.location.hostname;
function ajaxPage(url, containerId){
var pageRequest = false;
pageRequest = new XMLHttpRequest();
pageRequest.onreadystatechange = function(){
loadpage(pageRequest, containerId);
}
preventCache = (url.indexOf("?")!=-1)? "&"+new Date().getTime() : "?"+new Date().getTime();
pageRequest.open('GET', url+preventCache, true);
pageRequest.send(null);
}
function loadpage(pageRequest, containerId){
if (pageRequest.readyState == 4 && (pageRequest.status==200 || window.location.href.indexOf("http") == -1)){
document.getElementById(containerId).innerHTML = pageRequest.responseText;
}
}
As you can see, I am passing a URL (of an HTML page) to the function ajaxPage()
The ajaxPage() function is being called in a separate .js file, like so:
ajaxPage('test.html', 'ajax-wrapper');
Which is working, test.html is being loaded in the element with id 'ajax-wrapper', but no JavaScript in the test.html page is working.
Here is what the test.html page looks like (just plain HTML):
<div class="t-page-title">
View Thread
</div>
<script>
alert('hello');
</script>
Even a simple alert('hello'); on the loaded HTML is not firing. The page is not being cached, so that is not the issue. I would know what to do if I was using jQuery, but I am a bit stumped with finding a JavaScript only solution. Any suggestions?
When you use innerHTML, the tags get copied to the destination element, but scripts are not executed. You need an additional eval step to execute the scripts.
jQuery has a function for that called globalEval, without jQuery you'll need to write your own.
[Update] Here is a variation with an iframe that might help address your issue: http://jsfiddle.net/JCpgY/
In your case:
ifr.src="javascript:'"+pageRequest.responseText+"'";
The standard behavior with a div: http://jsfiddle.net/JCpgY/1/

Controlling the scope of a document.write call coming from a third party

I'm writing a webpage that relies on an external javascript file (that I have no control of), which returns data by using document.write's. Is there any way to dynamically call the function without it overwriting the whole document? Here's the most concise code I can think of:
<html>
<head>
<script type="text/javascript">
function horriblefunction () {
document.write("new text");
}
</script>
</head>
<body>
Starting Text...
<div id="pleasewriteinme"></div>
Other text...
<button onclick="horriblefunction();">Click</button>
</body>
</html>
The idea beginning that without altering "horriblefunction()" (as it's external) the new text could be placed in the div instead of overwriting the page. Is this possible or does the function have to be called inside the div as the page is created?
Thanks for you help
The only way to use document.write after the page has finished rendering is to temporarily replace the function with one of your own making that will shove the content into a div. E.g.
function horriblefunction() {
var old_dw = document.write;
document.write = function(text) {
document.getElementById( 'some_div' ).innerHTML = text;
}
// now call your external JS function that uses document.write
document.write = old_dw;
}
This will work as long as the external JS is already loaded and you're just calling a function. If you need to load the JS (say, by inserting a new <script> tag into the DOM) remember that that operation is asynchronous, and you'll need to watch the DOM to know when it's safe to restore the old version of document.write.
Try using dynamic script loading from http://bezen.org/javascript/index.html
bezen.domwrite.js - Captures document.write and writeln for the safe loading of external scripts after page load.

Categories

Resources