JSONP Works on browsing to URL but not on refresh - javascript

On a page I have 2 javascripts. The first script (A.js) appends a script to the head of the parent page in order to pass JSONP. The first script then takes the JSONP array data and puts it into an array for the second script to use. When I go to the hard URL everything works fine. If I F5 it doesn't work. If I add an alert to the first script right after the JSONP is done then everything works.
So, I am guessing that when refreshing, for some reason, everything happens much faster and therefore the appending of the script doesn't have a chance to happen and the array never receives the data.
How can I fix this?
Main Page:
<script src="A.js"></script>
<script type="text/javascript">
ArrayValueOnMainPage = ArrayValue.FirstValue
</script>
A.js:
//Fail safe default
ArrayValue = {"FirstValue":["NULL"]};
function initiate(data){
ArrayValue = data;
}
function loadJSONP(url){
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
head.appendChild(script);
}
loadJSONP('/test.json');
test.json:
initiate({"FirstValue":["Hello"]});
On hard browse to URL FirstValue is passed as Hello.
On F5 refresh FirstValue is passed as NULL.

Related

Javascript: best way to wait for script loaded synchonously before executing function?

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>

HTML/JavaScript Script Injection Exception

I tried to write a bookmarklet which depends on another script. For this my bookmarklet includes a function like this:
function load(url, callback) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.async = false;
script.onload = callback;
document.head.appendChild(script);
}
The callback function is called on most pages, but on some pages I get the following exception in the console and the script is not loaded (facebook.com is one example).
Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE)
An example of a bookmarklet:
javascript:function%20load(url,callback){var%20script=document.createElement('script');script.type='text/javascript';script.src=url;script.onload=callback;document.head.appendChild(script);}load('http://code.jquery.com/jquery-1.11.1.min.js',function(){console.log('Loaded');})
I use FireFox 29 on Ubuntu 12.04. If it is executed a "Loaded" should a appear in the console. On the first load an additional access to the resource is visible in the console. But as written above on e.g. facebook.com nothing happens at all. Neither is the script loaded nor is the callback called.
It was quite likely due to XSS from the bookmarklet itself. FF 35.0 doesn't have an error anymore and shows a well formatted message.

Asynchronous PHP page loading within javascript tags

I have the following tag which loads a PHP and I need it to be loaded asynchronously thus everything in the containing page is load even if the called PHP file takes longer to return the value (or even is server is down).
<script language="JavaScript"
src="http://www.server.com/phpfile.php">
</script>
I've tried replacing it with the code use by FB and other methods for JS asynchronous loading but it does not work. The issue is that in this case it is a PHP file the one that is called, not a JS file.
I tried the following but it does not work when the called PHP script plugs HTML code (such as a div with an image) with document.write:
<script language="JavaScript">
(function () {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true; s.src = 'server.com/phpfile.php';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})();
</script>
Any ideas?
Thank you.

Injected javascript does not execute

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/

How can I run a fallback copy of jQuery after the DOM is loaded?

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>' }
}

Categories