Externally loading a script, but my script was placed by the client above jQuery (which is a requirement), as such, my script does not work.
I am trying to make my code wait until jQuery has loaded before executing, but I am having difficulty with nested functions within my code; specifically $(x).hover, or $(x).click etc.
I can separate my functions without much trouble, which include jQuery selectors (but they won't be called unless 'x y or z' is done (i.e. until after jQuery is loaded).
I don't know how to have the hover, click etc implemented as they don't work within my $(document).ready(function(){... which is located within the onload yourFunctionName described below - with thanks to user #chaos
Link to onload hook: https://stackoverflow.com/a/807997/1173155
and a quote of the above link:
if(window.attachEvent) {
window.attachEvent('onload', yourFunctionName);
} else {
if(window.onload) {
var curronload = window.onload;
var newonload = function() {
curronload();
yourFunctionName();
};
window.onload = newonload;
} else {
window.onload = yourFunctionName;
}
}
Thanks in advance for any help with this.
I have also looked into a loop that checks if jQuery is activated before continueing, but did not implement it as I found that JavaScript does not have a sufficient sleep method that sleeps that specific script.
Solution:
if(typeof jQuery === "undefined"){
if(window.attachEvent) {
window.attachEvent('onload', myLoadFunction);
} else {
if(window.onload) {
var curronload = window.onload;
var newonload = function() {
curronload();
myLoadFunction();
};
window.onload = newonload;
} else {
window.onload = myLoadFunction;
}
}
}
else {
myLoadFunction();
}
Related
I try to display progress bar when page loading. I want change width of progress bar after js files loaded .At the final after load all documents set with of progress bar to 100% .Now I need to recognize js files loading with javascript.
Is this possible ? Please advice.
For internal js files loading recognition:
As functions and variables can be accessed from another file you can set the value of global progress variable and display it's value by calling the function
//on page or head js file
var progress = 0;
function displayProgress()
{
//show progress based on 'progress' variable
}
//file1.js
progress += 10;
displayProgress();
...
//file2.js
progress += 20;
displayProgress();
...
For external js files there is good article. The main idea is to periodically check existense of external functions (typeof fixpng =='function') and if it exist - stop checking and display progress.
Here's the JavaScript code to load the external library with a
callback passed in:
function loadExtScript(src, callback) { var s = document.createElement('script'); s.src = src; document.body.appendChild(s); // if loaded...call the callback }
Firefox allows you to listen for the onload event on the script
element:
s.onload = callback;
With Internet Explorer you can wait for a state change on the script
element:
s.onreadystatechange = function() { if ( this.readyState != "loaded"
) return; callback.call(); }
The problem comes with Safari - there's no event change for Safari, so
we can't tell when the script has loaded. This is the solution I came
up with (and this solution should also work with Opera):
function loadExtScript(src, test, callback) { var s =
document.createElement('script'); s.src = src;
document.body.appendChild(s);
var callbackTimer = setInterval(function() {
var call = false;
try {
call = test.call();
} catch (e) {}
if (call) {
clearInterval(callbackTimer);
callback.call();
} }, 100); }
The function takes a test as a parameter. Since you are the designer
of the app, you'll know what successful test is. Once this test is
true, it will execute the callback. A simple test could be to check
whether a function exists, for example:
loadExtScript('/fixpng.js', function() { return (typeof fixpng ==
'function'); }, myCallbackFunction);
If you know at least one defined namespace (almost all libraries and plugins have it: e.g. jQuery, jQuery.ui, jQuery.mobile, toastr, DataTable, etc.) or one global variable name introduced by the script files which are being loaded, then you can do this:
(function(undefined) {
var scriptFilesLoaded = false,
files = [],
timer = setInterval(function(){
try {
files = [
jQuery,
jQuery.mobile,
jQuery.ui,
someGlobalVariableName
];
if(files.indexOf(undefined)<0){
scriptFilesLoaded = true;
clearInterval(timer);
}
}
catch(e) {
console.warn('Preloader in action: Script files not loaded yet.');
}
},200);
})();
It doesn't matter if the script file is remote or local.
i've been fighting with this problem from a while now. I think it all started when i've added my website to google webmaster's tool: at some point I started receiving an alert saying my website was missing the tracking code, but actually it was there, and even though it said it was missing, i still got my analytics stats.
at that time, the code was include in a .js file containing all of my javascript. it was included right before the </body> tag and it was loaded this way:
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "js/build/production.min.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;
</script>
</body>
i've found this script on some blog (http://www.giftofspeed.com/defer-javascripts/) and I use this to defer javascript loading to make the page to load faster.
at some point i thought deferring the ga code was the problem (as it's all in that production.min.js file) so i've moved the ga code outside of that. and now it's like this
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "js/build/production.min.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;
</script>
<script>
//my google analytics code here
</script>
</body>
once I did this, the alert got solved BUT the tracking is not happening anymore.
I've been using GA from ages and I never had problems like these. What could this be? I feel like i've tried it all.
Approach for modern browsers
https://github.com/jfriend00/docReady/blob/master/docready.js
Your customisation:
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "js/build/production.min.js";
document.body.appendChild(element);
}
(function(funcName, baseObj) {
"use strict";
// The public function name defaults to window.docReady
// but you can modify the last line of this function to pass in a different object or method name
// if you want to put them in a different namespace and those will be used instead of
// window.docReady(...)
funcName = funcName || "docReady";
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;
// call this when the document is ready
// this function protects itself against being called more than once
function ready() {
if (!readyFired) {
// this must be set to true before we start calling callbacks
readyFired = true;
for (var i = 0; i < readyList.length; i++) {
// if a callback here happens to add new ready handlers,
// the docReady() function will see that it already fired
// and will schedule the callback to run right after
// this event loop finishes so all handlers will still execute
// in order and no new ones will be added to the readyList
// while we are processing the list
readyList[i].fn.call(window, readyList[i].ctx);
}
// allow any closures held by these functions to free
readyList = [];
}
}
function readyStateChange() {
if ( document.readyState === "complete" ) {
ready();
}
}
// This is the one public interface
// docReady(fn, context);
// the context argument is optional - if present, it will be passed
// as an argument to the callback
baseObj[funcName] = function(callback, context) {
// if ready has already fired, then just schedule the callback
// to fire asynchronously, but right away
if (readyFired) {
setTimeout(function() {callback(context);}, 1);
return;
} else {
// add the function and context to the list
readyList.push({fn: callback, ctx: context});
}
// if document already ready to go, schedule the ready function to run
// IE only safe when readyState is "complete", others safe when readyState is "interactive"
if (document.readyState === "complete" || (!document.attachEvent && document.readyState === "interactive")) {
setTimeout(ready, 1);
} else if (!readyEventHandlersInstalled) {
// otherwise if we don't have event handlers installed, install them
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener("DOMContentLoaded", ready, false);
// backup is window load event
window.addEventListener("load", ready, false);
} else {
// must be IE
document.attachEvent("onreadystatechange", readyStateChange);
window.attachEvent("onload", ready);
}
readyEventHandlersInstalled = true;
}
}
})("downloadJSAtOnload", window);
// modify this previous line to pass in your own method name
// and object for the method to be attached to
</script>
I try to load some js files dynamically,for example:
function openInforWindow(){
//check if the InforWinow.js has been loaded or not
if(window.InforWindow){
//do the right thing
}
else {
loadJs('xxxxxx/InforWindow.js');
// do the right thing
//but here ,the infowindow is not definded yet.
}
}
function loadJs(filename){
var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", filename)
if (typeof fileref!="undefined")
document.getElementsByTagName("head")[0].appendChild(fileref)
}
How to make sure that the vars or functions in the js which is dynamically loaded can be add to the javascript execute environment so I can use them ?
adding a script element isn't a blocking operation, this means that your loadJs method returns immediately when your external script isn't even loaded (nor interpreted). You have to wait for it to load.
function openInforWindow(){
//check if the InforWinow.js has been loaded or not
if(window.InforWindow){
//do the right thing
}
else {
var loadHandler = function() {
//do stuff with inforWindow
};
loadJs('xxxxxx/InforWindow.js', loadHandler);
}
}
function loadJs(filename, handler){
var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", "js");
fileref.onreadystatechange = function () {
if (this.readyState == 'complete')handler();
};
fileref.onload = handler;
if (typeof fileref!="undefined")
document.getElementsByTagName("head")[0].appendChild(fileref);
}
One approach could be to load the script using jQuery's AJAX loader. Example below:
function loadJs(filename, functionToCall){
$.getScript(filename, functionToCall);
}
Now, you just need to call loadJs("script.js", callback);, and it will first completely load script.js, and then run callback().
You can dynamically insert a <script/> tag into your document, here is a script that will work in firefox/chrome, you may need a bit of tweaking in IE:
loadJs = function(src) {
var script = document.createElement('SCRIPT');
script.setAttribute('src', src);
document.getElementsByTagName('HEAD')[0].appendChild(script);
}
Then wait for the document.onload event to fire, your window.InforWindow should be loaded at that stage.
document.addEventListener('load', function () {
// Your logic that uses window.InforWindow goes here
}, false);
Note that IE does the load event listener slightly differently:
document.attachEvent('onload', function() {
// Your logic that uses window.InforWindow goes here
});
If I have a script that is loaded dynamically, I want it to wait until the DOM is ready before executing code. However, if the script loads too slowly, the DOM will already be ready and therefore the DOM-Ready function will not run.
No frameworks, please, I'm relying on pure JavaScript.
Thanks in advance!
Without a listener there's no 100% reliable way to ensure that the entire DOM is loaded. You can do something like this:
var myChecker = setInterval(function () {
var checkElem = document.getElementById('myRefElement');
if (checkElem != null) {
clearInterval(myChecker);
myFunction();
}
}, 100);
That'll wait until some target element you care about exists.
Part way down on this page: http://dean.edwards.name/weblog/2006/06/again/ you will find this code, which is what I use to do what you are asking about:
I leave the comment with the code as I didn't write it:
// Dean Edwards/Matthias Miller/John Resig
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
// do stuff
};
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
/* for Internet Explorer */
/*#cc_on #*/
/*#if (#_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
init(); // call the onload handler
}
};
/*#end #*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = init;
Very simple - put your script immediately before the closing body tag (if you have one). It doesn't guarantee that the DOM is ready, but it's more reliable that DOM ready listeners and runs earlier than load listeners.
Here are a couple of pure javascript domready events:
http://snipplr.com/view/6029/domreadyjs/
http://www.geekdaily.net/2007/07/27/javascript-windowonload-is-bad-mkay/
snippet that checks the document.readyState
http://www.dustindiaz.com/smallest-domready-ever
I want to fire and event when the DOM has completely loaded. I checked out document.readyState but it's not an event. I want to fire it when the readyState is complete. How do I do that?
Some easy googling point me to this code:
// alternative to DOMContentLoaded
document.onreadystatechange = function () {
if (document.readyState == "complete") {
initApplication();
}
}
And to this link
Handle the window.load event.
This will only fire when all external resources (including images) have loaded.
Taken from another post, however, you could do it like this:
var alreadyrunflag = 0; //flag to indicate whether target function has already been run
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function() {
alreadyrunflag = 1;
// perform what you need to
}, false);
} else if (document.all && !window.opera) {
var contentloadtag = document.getElementById("contentloadtag");
contentloadtag.onreadystatechange = function() {
if (this.readyState == "complete") {
alreadyrunflag = 1;
// perform what you need to
}
}
}
//fallback
window.onload = function() {
setTimeout(function() {
if (!alreadyrunflag) {
// perform what you need to
}
}, 0);
}
This checks that the DOM is fully loaded, however, if it isn't, it falls back to onload. You can obviously manipulate this though.
Also, if JQuery is an option, you can achieve the same effect by using just one simple function:
$(document).ready(function() {
// Handler for .ready() called.
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
You can do it like this:
function startupApplication(anyFunction) {
document.onreadystatechange = function () {
document.onreadystatechange = () =>
document.readyState === "complete" ? anyFunction() : undefined;
};
}
startupApplication(() => {
// Put your code here ...
});
See my FiddleJS with comments and logs for education purposes: click here
For anyone already using the jQuery library the ready function can be used to handle this.
Otherwise the solution from #Neal will achieve the same functionality without needing to add an additional dependency.