I am taking a page that does not have jquery referenced in the dom. I need to use some of the jquery functionality, so i figured the best bet is to inject jquery into the existing dom. I got the function idea from Load jQuery with Javascript and use jQuery and How to include jQuery dynamically in any website using pure javascript ....none of these solutions seem to work for me. I am still getting an error not recognizing the jquery selector.
(function() {
function getScript(url, success) {
var script = document.createElement('script');
script.src = url;
var head = document.getElementsByTagName('head')[0],
done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function() {
if (!done && (!this.readyState
|| this.readyState == 'loaded'
|| this.readyState == 'complete')) {
done = true;
success();
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
head.appendChild(script);
}
getScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js',function() {
// Yay jQuery is ready \o/
});
cards = $('div:first');
$('body').empty().append(cards);
// Delete first and second child divs
first = $('div:first div:first');
$('div:first div:first').css('position', '').css('left', '').css('z-index', '').css('height', '250px').remove();
second = $('div:first div:first');
$('div:first div:first').css('position', 'relative').css('left', '').css('z-index', '').remove();
$('body').empty().append(first).append(second);
})();
You're supposed to move your own code into the callback, to where it says // Yay.... Only then is your code run after jQuery was loaded.
getScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js', function() {
// Yay jQuery is ready \o/
$('body').empty().append($('div:first'));
// Delete first and second child divs
for (var i = 0; i < 2; i++) {
$('div:first div:first').remove();
}
});
Related
I have a TextBox and a Button:
If the value inside the Textbox is 1 (just emulating a condition)) I need to load jQuery on the fly and use a document Ready function :
I tried this :
function work() //when button click
{
if (document.getElementById('tb').value == '1')
{
if (typeof jQuery == 'undefined')
{
var script = document.createElement('script');
script.src = "http://code.jquery.com/jquery-git2.js";
document.getElementsByTagName('head')[0].appendChild(script);
$(document).ready(function ()
{
alert('');
});
}
}
}
But it says :
Uncaught ReferenceError: $ is not defined
I assume it's because the line : $(document).ready(function ()....
But I don't understand why there is a problem , since i'm, loading jQuery BEFORE I use $...
Question :
How can I fix my code to work as desired ?
JSBIN
You are missing the script onload handler:
var script = document.createElement('script');
// do something with script
// onload handler
script.onload = function () {
// script was loaded, you can use it!
};
Your function becomes:
function work() {
if (document.getElementById('tb').value != '1') { return; }
if (typeof jQuery != 'undefined') { return; }
// jQuery is undefined, we will load it
var script = document.createElement('script');
script.src = "http://code.jquery.com/jquery-git2.js";
document.getElementsByTagName('head')[0].appendChild(script);
// load handler
script.onload = function () {
// jQuery was just loaded!
$(document).ready(function () {
alert('');
});
};
}
Also, do not forget script.onreadystatechange for IE compatibility.
script.onreadystatechange = function () {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
// script was loaded
}
}
Also seems that YepNope would be a good option, too.
JSBIN DEMO
Using YepNope would probably a good option in this case.
yepnope([
{
test: window.jQuery,
nope: 'path/url-to-jquery.js',
complete: function() {
$(document).ready(function() {
//whatever you need jquery for
});
}
}
]);
You can just put that in the head of your document, and it will only load jquery if window.jQuery isn't defined. It's much more reliable (and simpler) than script.onload or script.onreadystatechange. the callback complete will only be called once jquery is loaded, so you can be sure that $ will be defined at that point.
Note: if you're using Modernizr.js on your site, there's a good chance yepnope is already bundled into that script.
I have a whole bunch of javascript files I need to load in order. However, one of them is not loading in ie7.
Here's the function that does the loading:
function loadScript(url, callback){
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = url;
// Attach handlers for all browsers
var done = false;
script.onload = script.onreadystatechange = function()
{
if( !done && ( !this.readyState
|| this.readyState == "loaded"
|| this.readyState == "complete") )
{
done = true;
// Continue your code
callback();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
head.appendChild(script);
}
And the function calls:
loadScript('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){
loadScript('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js',function(){
loadScript('http://XXX/js/data.php?rand='+Math.random(),function(){
loadScript('http://XXX/js/jquery.inject.js?rand='+Math.random(),function(){
console.log('a');
loadScript('XXX/js/press.js?rand='+Math.random(),function(){
console.log('b');
inject_press();
});
});
});
});
});
The file that doesn't load i jquery.inject.js, whos code is
console.log('y');
jQuery.prototype.inject = function(a){
...
}
Again this works in all browsers except ie7. The output is
a
b
This is not the best way how to load ECMAscript files. I would name that files to sort them and then load using ASP.NET 4.5 bundling.
I have a initializor.js that contains the following:
if(typeof jQuery=='undefined')
{
var headTag = document.getElementsByTagName("head")[0];
var jqTag = document.createElement('script');
jqTag.type = 'text/javascript';
jqTag.src = 'jquery.js';
headTag.appendChild(jqTag);
}
I am then including that file somewhere on another page. The code checks if jQuery is loaded, and if it isn't, adds it to the Head tag.
However, jQuery is not initializing, because in my main document, I have a few events declared just to test this. I also tried writing some jQuery code below the check, and Firebug said:
"jQuery is undefined".
Is there a way to do this? Firebug shows the jquery inclusion tag within the head tag!
Also, can I dynamically add code into the $(document).ready() event? Or wouldn't it be necessary just to add some Click events to a few elements?
jQuery is not available immediately as you are loading it asynchronously (by appending it to the <head>). You would have to add an onload listener to the script (jqTag) to detect when it loads and then run your code.
e.g.
function myJQueryCode() {
//Do stuff with jQuery
}
if(typeof jQuery=='undefined') {
var headTag = document.getElementsByTagName("head")[0];
var jqTag = document.createElement('script');
jqTag.type = 'text/javascript';
jqTag.src = 'jquery.js';
jqTag.onload = myJQueryCode;
headTag.appendChild(jqTag);
} else {
myJQueryCode();
}
To include jQuery you should use this:
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="jquery.js">\x3C/script>')</script>
it uses the Google CDN but provides a fallback an has a protocol relative URL.
Note: Be sure to change the version number to the latest version
if window.jQuery is defined, it will not continue to read the line since it is an or that already contains a true value, if not it wil (document.)write the value
see: theHTML5Boilerplate
also: you forgot the quotes, if jQuery is not defined:
typeof window.jQuery === "undefined" //true
typeof window.jQuery == undefined //false ,this is wrong
you could also:
window.jQuery === undefined //true
If you're in an async function, you could use await like this:
if(!window.jQuery){
let script = document.createElement('script');
document.head.appendChild(script);
script.type = 'text/javascript';
script.src = "//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js";
await script.onload
}
/* Your jQuery code here */
If you're not, you can use (async function(){/*all the code*/})() to wrap and run all the code inside one
.
Alternatively, refactoring Adam Heath's answer (this is more readable IMO). Bottom line, you need to run the jQuery code AFTER jQuery finished loading.
jQueryCode = function(){
// your jQuery code
}
if(window.jQuery) jQueryCode();
else{
var script = document.createElement('script');
document.head.appendChild(script);
script.type = 'text/javascript';
script.src = "//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js";
script.onload = jQueryCode;
}
Or you could also wrap it in a function to change the order of the code
function runWithJQuery(jQueryCode){
if(window.jQuery) jQueryCode();
else{
var script = document.createElement('script');
document.head.appendChild(script);
script.type = 'text/javascript';
script.src = "//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js";
script.onload = jQueryCode;
}
}
runWithJQuery(function jQueryCode(){
// your jQuery code
})
The YepNope loader can be used to conditionally load scripts, has quite a nice, easy to read syntax, they have an example of just this on their website.
You can get it from their website.
Example taken from their website:
yepnope([{
load: 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
complete: function () {
if (!window.jQuery) {
yepnope('local/jquery.min.js');
}
}
}
This site code is solved my problem.
function loadjQuery(url, success){
var script = document.createElement('script');
script.src = url;
var head = document.getElementsByTagName('head')[0],
done = false;
head.appendChild(script);
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function() {
if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
done = true;
success();
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
}
if (typeof jQuery == 'undefined'){
loadjQuery('http://code.jquery.com/jquery-1.10.2.min.js', function() {
// Write your jQuery Code
});
} else {
// jQuery was already loaded
// Write your jQuery Code
}
http://99webtools.com/blog/load-jquery-if-not-already-loaded/
This is old post but I create one workable solution tested on various places.
Here is the code.
<script type="text/javascript">
(function(url, position, callback){
// default values
url = url || 'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js';
position = position || 0;
// Check is jQuery exists
if (!window.jQuery) {
// Initialize <head>
var head = document.getElementsByTagName('head')[0];
// Create <script> element
var script = document.createElement("script");
// Append URL
script.src = url;
// Append type
script.type = 'text/javascript';
// Append script to <head>
head.appendChild(script);
// Move script on proper position
head.insertBefore(script,head.childNodes[position]);
script.onload = function(){
if(typeof callback == 'function') {
callback(jQuery);
}
};
} else {
if(typeof callback == 'function') {
callback(jQuery);
}
}
}('https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js', 5, function($){
console.log($);
}));
</script>
Explanation you can find HERE.
I have an external js file being loaded (which I cannot modify) with document.createElement() and I need to access a variable from it. The problem is, I don't know when does it finish loading. I tried jQuery's document ready function but it seems to deploy sooner than the javascript file. I am able to access the variable like this though:
setTimeout("console.log(swifttagdiv.firstChild.firstChild.src)", 5000);
but this is just a test to see if the variable is global. Any ideas?
You can inject the script by using Javascript instead of putting it in your page. This way you can control when it is loaded.
Here's a function I use to inject code in pages dynamically:
function inject(src, cb, target){
target = target || document.body;
var s = document.createElement('SCRIPT');
s.charset = 'UTF-8';
if(typeof cb === 'function'){
s.onload = function(){
cb(s);
};
s.onreadystatechange = function () {
(/loaded|complete/).test(s.readyState) && cb(s);
};
}
s.src = src;
target.appendChild(s);
return s;
}
to use it:
inject('/path/to/file.js', function(script){
//your code here
})
var checkvarint = setInterval(function(){
if(swifttagdiv.firstChild.firstChild.src){
varLoaded(); clearInterval(checkvarint);
}
},10);
function varLoaded(){
alert("LOADED!");
alert(swifttagdiv.firstChild.firstChild.src);
}
Mic's answer is great.
Here is the same thing only less abstracted, perhaps it will be instructive
var scriptElement = document.createElement( 'script' );
scriptElement.type = "text/javascript";
scriptElement.src = "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core-debug.js";
function loadHandler() {
alert( 'loaded' );
}
// for ie
scriptElement.onreadystatechange = function () {
if( this.readyState == 'complete' ){
loadHandler();
}
}
// for others
scriptElement.onload= loadHandler;
document.getElementsByTagName('head')[0].appendChild( scriptElement );
Problem:
Load js files asynchronously, then check to see if the dom is loaded before the callback from loading the files is executed.
edit: We do not use jQuery; we use Prototype.
edit: added more comments to the code example.
I am trying to load all of my js files asynchronously so as to keep them from blocking the rest of the page. But when the scripts load and the callback is called, I need to know if the DOM has been loaded or not, so I know how to structure the callback. See below:
//load asynchronously
(function(){
var e = document.createElement('script');
e.type = "text/javascript";
e.async = true;
e.src = srcstr;
// a little magic to make the callback happen
if(navigator.userAgent.indexOf("Opera")){
e.text = "initPage();";
}else if(navigator.userAgent.indexOf("MSIE")){
e.onreadystatechange = initPage;
}else{
e.innerHTML = "initPage();";
}
// attach the file to the document
document.getElementsByTagName('head')[0].appendChild(e);
})();
initPageHelper = function(){
//requires DOM be loaded
}
initPage = function(){
if(domLoaded){ // if dom is already loaded, just call the function
initPageHelper();
}else{ //if dom is not loaded, attach the function to be run when it does load
document.observe("dom:loaded", initPageHelper);
}
}
The callback gets called properly due to some magic behind the scenes that you can learn about from this Google talk: http://www.youtube.com/watch?v=52gL93S3usU&feature=related
What's the easiest, cross-browser method for asking if the DOM has loaded already?
EDIT
Here's the full solution I went with.
I included prototype and the asynchronous script loader using the normal method. Life is just so much easier with prototype, so I'm willing to block for that script.
<script type="text/javascript" src="prototype/prototype.js"></script>
<script type="text/javascript" src="asyncLoader.js"></script>
And actually, in my code I minified the two files above and put them together into one file to minimize transfer time and http requests.
Then I define what I want to run when the DOM loads, and then call the function to load the other scripts.
<script type="text/javascript">
initPage = function(){
...
}
</script>
<script type="text/javascript">
loadScriptAsync("scriptaculous/scriptaculous.js", initPage);
loadScriptAsync("scriptaculous/effects.js", initPage);
loadScriptAsync("scriptaculous/controls.js", initPage);
...
loadScriptAsync("mypage.js", initPage);
</script>
Likewise, the requests above are actually compressed into one httpRequest using a minifier. They are left separate here for readability. There is a snippet at the bottom of this post showing what the code looks like with the minifier.
The code for asyncLoader.js is the following:
/**
* Allows you to load js files asynchronously, with a callback that can be
* called immediately after the script loads, OR after the script loads and
* after the DOM is loaded.
*
* Prototype.js must be loaded first.
*
* For best results, create a regular script tag that calls a minified, combined
* file that contains Prototype.js, and this file. Then all subsequent scripts
* should be loaded using this function.
*
*/
var onload_queue = [];
var dom_loaded = false;
function loadScriptAsync(src, callback, run_immediately) {
var script = document.createElement('script');
script.type = "text/javascript";
script.async = true;
script.src = src;
if("undefined" != typeof callback){
script.onload = function() {
if (dom_loaded || run_immediately)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
script.onreadystatechange = function() {
if (script.readyState == 'complete'){
if (dom_loaded || run_immediately)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
}else if(script.readyState == 'loaded'){
eval(script);
if (dom_loaded || run_immediately)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
}
};
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
}
document.observe("dom:loaded", function(){
dom_loaded = true;
var len = onload_queue.length;
for (var i = 0; i < len; i++) {
onload_queue[i]();
}
onload_queue = null;
});
I added the option to run a script immediately, if you have scripts that don't rely on the page DOM being fully loaded.
The minified requests actually look like:
<script type="text/javascript" src="/min/?b=javascript/lib&f=prototype/prototype.js,asyncLoader.js"></script>
<script type="text/javascript"> initPage = function(e){...}</script>
<script type="text/javascript">
srcstr = "/min/?f=<?=implode(',', $js_files)?>";
loadScriptAsync(srcstr, initPage);
</script>
They are using the plugin from: [http://code.google.com/p/minify/][1]
What you need is a simple queue of onload functions. Also please avoid browser sniffing as it is unstable and not future proof. For full source code see the [Demo]
var onload_queue = [];
var dom_loaded = false;
function loadScriptAsync(src, callback) {
var script = document.createElement('script');
script.type = "text/javascript";
script.async = true;
script.src = src;
script.onload = script.onreadystatechange = function() {
if (dom_loaded)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
}
function domLoaded() {
dom_loaded = true;
var len = onload_queue.length;
for (var i = 0; i < len; i++) {
onload_queue[i]();
}
onload_queue = null;
};
// Dean's dom:loaded code goes here
// do stuff
domLoaded();
Test usage
loadScriptAsync(
"http://code.jquery.com/jquery-1.4.4.js",
function() {
alert("script has been loaded");
}
);
You can always put your initial loader script at the bottom, right before the closing body tag.