I'm trying to write a piece of javascript that integrates a webpage with an external system. Currently, what I have is a very small amount of code that dynamically inserts a script element into the page.
$(document).ready(function() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://example.com/example.php?arg1=1&arg2=2";
document.body.appendChild(script);
});
The JS returned by the external system is a large one-line document.write call which writes a table to the page.
document.write('<table><tr><td>blah</td></tr></table>');
When I inject this script element into the page, I can see it using a DOM inspector, but the script does not appear to execute. If I put the script element into the HTML manually, the javascript executes just fine (so it's not a same origin policy or malformed html error...), but I'd like it to be dynamic.
Any ideas why the javascript isn't executing?
Using document.write after the DOM is ready will replace the contents of the page with whatever it is you're writing.
I suggest using one of the actual DOM manipulation methods if you want to insert anything into a page.
As far as the script not executing, are you positive it's being attached correctly? Have you tried setting a javascript breakpoint on the included script to verify that this is the case?
Try to use this code (it the same use by google for analytics or facebook).
Put it on the bottom of your page ;)
<script type="text/javascript">
(function() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = '/example.php?arg1=1&arg2=2';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(script, s);
})();
</script>
OR as davidbuzatto suggest, you have to use $.getScript() which is a shorthand $.ajax() function.
$(document).ready(function() {
$.getScript("/example.php?arg1=1&arg2=2", function(data, textStatus, jqxhr) {
console.log(data); //data returned
console.log(textStatus); //success
console.log(jqxhr.status); //200
console.log('Load was performed.');
});
});
Edit :
Seens you have probably a cross-domain restriction, just try to use relative url "/example.php?arg1=1&arg2=2" instead of the full url for the include.
Or if it's not the same web server, use a cross-domain.xml file.
Because you are just including it, not executing. As you are using jQuery, take a look in the $.getScript() function.
http://api.jquery.com/jQuery.getScript/
It will fit your needs. This function is an Ajax function, so take care, because its behavior is asynchronous. Use its callbacks to execute code that is based in the loaded script.
Edit: Felix corrected me about the script execution, but I still think that you may give the function a try.
i think you need to use JSONP to achieve that and using a call back function to append it to body tag
$(document).ready(function() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://example.com/example.php?arg1=1&arg2=2&callback=showit(data)";
document.body.appendChild(script);
});
function showit(data){document.write(data);}
I've always seen this done more like:
document.write('<scr' + 'ipt>---scripthere---' + '</scr' + 'ipt>');
I'm assuming it is for similar reasons. Try that instead of creating a "real" script element.
Why not just stick the JS in a separate window/iframe where it executes and displays the tables correctly, and then pull that table using AJAX to that page?
JQuery AJAX is the easiest to use IMO:
http://api.jquery.com/jQuery.ajax/
Related
I want to create my own asset loader. To load external scripts, I used following javascript
function loadScript(src, callback) {
var script = document.createElement("script");
script.onload = function() {
document.head.appendChild(script);
callback();
};
script.src = src;
}
But I think this isn't the most elegant solution. This code snippet would make my HTML code ugly since it appends code to the head - for all of my dependencies.
So my question: is it possible to access to my external loaded code without using following line
document.head.appendChild(script);
Am I able to executes my script with pure js like
script.execute();
Or even better, is there a way to access to the data stored in my external js file? Like variable "bar", for example?
var foo = script.get("bar")
Could I even execute a function of the external file?
script.function(params)
It would be great to hear of your ideas and experiences!
Darth Moon
Edit: I forgot to exclude ajax. I know I could load code via ajax and executes it via eval(), but that won't be a good idea if you're testing code local since you need a Server (like an XAMPP Apache) to send ajax request to your local files.
You could try something like so as below.
Internal script:
function appendScript(src) {
var script = document.createElement(‘script’);
script.src = src;
document.head.appendChild(script);
}
External script:
function loadedScript() {
// run something
}
loadedScript()
The external code will just run loadedScript() once the file is loaded.
I have the following problem:
I load a page inside a modal dialog. This page uses jQuery as dependency. Since I already use jQuery on the main page, for me, it is always available. Now we have the usecase, that also different pages (hosted on different domains) need to load that page if necessary.
So, I check if the jQuery variable exists on this page and if yes, just go on with my code.
If it does not exist, on top of the template, I dynamically create a script element like this:
<script>
if(!window.jQuery)
{
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "path/to/jQuery";
document.getElementsByTagName('head')[0].appendChild(script);
}
</script>
And at the end of the template, I use a IIFE (to scope the jquery variable)
(function ($) {
.... code ....
})(jQuery);
However, since with this method, the script gets loaded asynchronously, sometimes I get the error: jQuery is undefined.
Now I came up by loading it synchronously, like this:
var xhrObj = new XMLHttpRequest();
// open and send a synchronous request
xhrObj.open('GET', "jquery.min.js", false);
xhrObj.send('');
// add the returned content to a newly created script tag
var se = document.createElement('script');
se.type = "text/javascript";
se.text = xhrObj.responseText;
document.getElementById('placeholder').appendChild(se);
This works fine, but the warning "Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. to the end user's experience." made me think.
However, now I changed my code and just said
if (!window.jQuery) {
document.write('<scr' + 'ipt src="jquery.js"' + '>' + '</scr' + 'ipt>');
}
on top of my Template.
Dear javascript gurus, is this a reliable solution?
Use the onload attribute in async javascript
<script async src="siteScript.js" onload="window.MyInitialisation()"></script>
In javascript it would look like this:
<script>
if(!window.jQuery)
{
var script = document.createElement('script');
script.type = "text/javascript";
script.async = "async";
script.defer = "defer";
script.onload = function() {window.MyInitialisation()}
script.src = "path/to/jQuery";
document.getElementsByTagName('head')[0].appendChild(script);
}
</script>
My code needs to load scripts on demand.
function includeJS(uri) {
return jQuery.getScript(uri);
}
includeJS('/path/to/script.js').always(function() {
// do something after script is loaded
});
The problem, though, is that the JS file will not be available in the Chrome Developer tools like other files that were included statically on the page. Due to this I cannot easily put break points.
Is there an alternative to jQuery.getScript that will also show the script in the Chrome Developer tools with the ability to put break points?
EDIT: Adding solution based on currently accepted answer (I will still consider other solutions, but this seems to work for me)
function includeJS(uri) {
var def = $.Deferred();
var script = document.createElement('script');
script.src = uri;
script.onload = function() {
def.resolve();
}
script.onerror = function() {
def.reject();
}
document.body.appendChild(script);
return def.promise();
}
You can simply append a script tag, and use an onload handler to execute post-load actions. Example: https://jsfiddle.net/0nu2dusu/
var script = document.createElement('script');
script.src = 'my_external_script.js';
script.onload = loadHandler;
document.body.appendChild(script);
You have slightly less control over failed loads than $.getScript offers, but the script does show up in dev tools.
Actually it's always there. Just take a look at an example from the jQuery.getScript() site. Here's how it looks like: http://i.imgur.com/LMFFAag.png.
The problem with .getScript() is that it never caches files requested, so on every call it adds some random string to prevent caching (what also prevents us from debugging code). But there's workaround for that:
Set global .ajax caching (not recommended) before you call .getScript():
$.ajaxSetup({
cache: true
});
Use direct .ajax() call (recommended):
$.ajax({
dataType: "script",
cache: true,
url: url
}
If it's your own script, you can always add a debugger; command anywhere to force browser to enter the debug mode (DevTools must be opened).
I have a javascript that sits on my server. I want to provide my visitors with javascript code that they can place on their servers in the way that Google Analytics does it. For example:
<script type="text/javascript" src="http://www.somedomain.com/script/script.js?id=2001102"></script>
I got everything working up to the point where I need to grab the id. I'm just not sure what to use for that.
I tried both location.href and location.search, but that gives me url + param of the file where the script is embeded, not "script.js?id=XSOMEIDX"
In script.js I have the following:
function requestContent() {
var script = document.createElement("script");
script.src = "http://www.somedomain.com/script/xss_script.php?id="I WANT TO INPUT ID HERE+"&url="+location.href;
document.getElementsByTagName("head")[0].appendChild(script);
}
Any how I can take id=XSOMEIDX and put it in xss_script.php?id= ?
Thanks in advance!
You can use URL rewritting to take id=XSOMEIDX and put it in xss_script.php?id=
A mod rewrite rule doing it would look like this :
RewriteRule ^/scripts/([a-zA-Z0-0]+)/script.js$ /scripts/script.php?id=$1
This way you could simply ask the people to include yoursite.com/scripts/{id}/scripts.js
how about setting up the external script tag with a certain attribute?
<script data-my-script="my_value" type="text/javascript" src="http://www.somedomain.com/script/script.js?id=2001102"></script>
in modern browsers you can then do
var scripts = document.querySelectorAll("script[src][data-my-script]");
$.each(scripts, function(i, script) { console.log(script.src); });
and iterate over the nodeList...
NOTE: querySelectorAll is not working cross-browser
NOTE: querySelectorAll is returning an array-like object
The following are the first lines of code in a <script> tag just above the closing body tag in my document (it specifies that a locally-served copy of jQuery is run in the event that Google's CDN fails):
if(!window.jQuery){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '/js/jquery.js';
var scriptHook = document.getElementsByTagName('script')[0];
scriptHook.parentNode.insertBefore(script, scriptHook);
}
jQuery(document).ready(function($){
// page behaviors
});
It does execute successfully, in the sense that if my computer is not connected to the Internet (this is a locally-served page), the local copy of jQuery is inserted. However, the document.ready() section below does not execute. I'm guessing this is because it is invoked before the fallback copy of jQuery takes effect. What's the proper practice for somehow "delaying" its execution so that either copy of jQuery will work properly?
Consider using an existing script loader such as yepnope. There's an example of exactly what you're trying to do on the home page.
You need to be sure that the script you are appending to the dom has finished loading before calling jQuery. You can do this with the technique described here:
if(!window.jQuery){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '/js/jquery.js';
script.onreadystatechange= function () {
if (this.readyState == 'complete') jQueryLoaded();
}
script.onload = jQueryLoaded;
var scriptHook = document.getElementsByTagName('script')[0];
scriptHook.parentNode.insertBefore(script, scriptHook);
}
function jQueryLoaded() { };
You can also fetch the jQuery contents as an Ajax request, create a script tag with those as the body of the script and append it. That would also work.
Try that
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.2.min.js"><\/script>')</script>
<script>
jQuery(document).ready(function($){
// page behaviors
});
</script>
This way the script tag will be loaded synchronously.
The question "of how do I cope with my CDN failing and load a file hosted on my server" seems to come up a few times lately.
Question I'd ask is whether adding yet more js is the way to achieve the resilience and what level of resilience do the js approaches really add e.g. if the CDN is down they'll be a quick failure but how well do these approaches if the CDN is slow to respond how well do these solutions cope?
An alternative way to approach this is treat it as an infrastructure problem...
Run a CDN based on a domain/sub-domain you own. Have automated monitoring on it's availability, when it fails switch the DNS over to a backup server (anycast may provide an alternative solution too)
A php solution would be something like this:
$google_jquery = 'https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js';
$fp = #fsockopen($google_jquery, 'r');
if (!$fp)
{
echo '<script type="text/javascript" src="js/jquery.js"></script>';
}
else
{
echo '<script src="'.$google_jquery.'"></script>' }
}