How to include script inside javascript code? - javascript

I want to implement the following code to improve my site performance and try to fire the script after scroll and wait 1 second.
<script type="text/javascript">
window.addEventListener('scroll',() =>
setTimeout(() => {
//Delay calendly
<script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script>
}, 1000);
);
</script>
I have this calendly script that I want to delay. The thing is I can't include the script inside another script, so, are there any way to make it?
Thanks!

You can do this with only the vanilla dom:
// ... something happens
var scr_elem = document.createElement('script');
scr_elem.type = 'text/javascript'
scr_elem.src = 'https://assets.calendly.com/assets/external/widget.js'
document.body.appendChild(scr_elem);

You can create a script dynamically and append to the head/body.
let timer;
window.addEventListener("scroll", () => {
if (!timer) {
timer = setTimeout(() => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://assets.calendly.com/assets/external/widget.js";
document.body.appendChild(script);
}, 1000);
}
});

Related

Dynamically Script Loading Zendesk Widget

I have been trying to save resources on the page by not loading the Zendesk Widget unless required.
If i manually add to a page the following tag everything works just fine:
<script id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=[MyKey]> </script>
As part of my page i have somewhere a div tag always present:
<div id="ze-snippet"> </div>
What i would like to have is, to do a "dynamic script load" of that <script> tag when a user clicks a button.
My current attempt looks like this:
window.onload = function () {
var zendeskWidgetOn = false;
document.getElementById('enable-zendesk-widget').addEventListener('click', function( event ) {
if (!zendeskWidgetOn) {
zendeskWidgetOn=true;
(function(d, script) {
script = d.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = function(){
console.log('script finished loading ...');
};
script.src = 'https://static.zdassets.com/ekr/snippet.js?key=[my key]';
d.getElementsByTagName('head')[0].appendChild(script);
}(document));
}
}, false);
};
The error i keep getting and i can't for the life of me figure out how to work around it is:
To have the widget script load only upon clicking the button, you just have to insert this to your html:
<script>
function loadZendeskWidget() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.id = 'ze-snippet';
script.async = true;
script.src = 'https://static.zdassets.com/ekr/snippet.js?key=<key>';
document.getElementsByTagName('head')[0].appendChild(script);
};
</script>
Just replace "key" with your own widget key.
Hope this helps.

How to load script dynamically without polluting the page namespace?

I need to dynamically load a JS file which exports a variable to the window object (e.g. React or jQuery) and get the exported value without changing the page window object. How can I do it using JavaScript?
It should work like this:
(function () {
var React = someMagic();
assertNotEmpty(React);
assertEmpty(window.React);
})();
What is my end goal: make a script for embedding to other websites. The script performs some actions with the page where it is installed, requires some dependencies, but the dependencies must not interfere with the page dependencies.
Using AMD or Require.js is not suitable because it changes the page scripts behaviour (they stop exporting variables to window) which can break the page.
Using a solution like this:
<script src="jquery.js"></script>
<script>
(function () {
var jQuery = jQuery.noConflict();
})();
</script>
Is also not suitable because it requires changing HTML while I can use only JavaScript.
Joining the script with the dependencies and wrapping it all with (function(){ ... })() is not suitable too.
Use Iframe to separate the namespaces. When a script is loaded inside an Iframe, it doesn't change the page namespace. A variable from an Iframe namespace can be exported to the page namespace when required.
// Imagine this is a content of the embedded script
const onMyJqueryLoad = jQuery => {
console.log('Page jQuery:', window.jQuery.fn.jquery, window.jQuery.ui);
console.log('My jQuery:', jQuery.fn.jquery, jQuery.ui);
};
const loadScript = (src, callback = () => {}, document = window.document) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = script.onerror = () => {
script.parentNode.removeChild(script);
callback();
};
script.src = src;
document.body.appendChild(script);
}
// Create an Iframe and do the dirty job inside it without affecting the page
let iframe = document.createElement('iframe');
iframe.style.position = 'absolute';
iframe.style.top = '-1000px';
iframe.style.width = 0;
iframe.style.height = 0;
iframe.onload = () => {
loadScript(
'https://cdn.jsdelivr.net/npm/jquery#1.12.4/dist/jquery.min.js',
() => loadScript(
'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.8.24/jquery-ui.min.js',
() => {
const jQuery = iframe.contentWindow.jQuery;
iframe.parentNode.removeChild(iframe);
iframe = null;
onMyJqueryLoad(jQuery);
},
iframe.contentWindow.document
),
iframe.contentWindow.document
);
iframe.onload = null;
};
document.body.appendChild(iframe);
<!-- The page -->
<script src="https://cdn.jsdelivr.net/npm/jquery#1.12.4/dist/jquery.min.js"></script>
Unfortunately the code doesn't work inside a Stack Overflow snippet because of the snippet sandboxing. You can view a demo on CodePen.

How to dynamically load and use/call a JavaScript file?

I need to dynamically load a JavaScript file and then access its content.
File test.js
test = function () {
var pub = {}
pub.defult_id = 1;
return pub;
}()
In this case it works:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/test.js"></script>
</head>
<body>
<script type="text/javascript">
console.log(test.defult_id);
</script>
</body>
</html>
But I need to load it dynamically, and that way it does not work:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
function loadjs(file) {
var script = document.createElement("script");
script.type = "application/javascript";
script.src = file;
document.body.appendChild(script);
}
loadjs('test.js');
console.log(test.defult_id);
</script>
</body>
</html>
Error: Uncaught ReferenceError: test is not defined(…)
You could do it like this:
function loadjs(file) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = file;
script.onload = function(){
alert("Script is ready!");
console.log(test.defult_id);
};
document.body.appendChild(script);
}
For more information read this article : https://www.nczonline.net/blog/2009/06/23/loading-javascript-without-blocking/
There is a great article which is worth reading for all the guys interesting in js script loading in www.html5rocks.com - Deep dive into the murky waters of script loading .
In that article after considering many possible solutions, the author concluded that adding js scripts to the end of body element is the best possible way to avoid blocking page rendering by js scripts thus speeding page loading time.
But, the author propose another good alternate solution for those people who are desperate to load and execute scripts asynchronously.
Considering you've four scripts named script1.js, script2.js, script3.js, script4.js then you can do it with applying async = false:
[
'script1.js',
'script2.js',
'script3.js',
'script4.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
Now, Spec says: Download together, execute in order as soon as all download.
Firefox < 3.6, Opera says: I have no idea what this “async” thing is, but it just so happens I execute scripts added via JS in the order they’re added.
Safari 5.0 says: I understand “async”, but don’t understand setting it to “false” with JS. I’ll execute your scripts as soon as they land, in whatever order.
IE < 10 says: No idea about “async”, but there is a workaround using “onreadystatechange”.
Everything else says: I’m your friend, we’re going to do this by the book.
Now, the full code with IE < 10 workaround:
var scripts = [
'script1.js',
'script2.js',
'script3.js',
'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];
// Watch scripts load in IE
function stateChange() {
// Execute as many scripts in order as we can
var pendingScript;
while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
pendingScript = pendingScripts.shift();
// avoid future loading events from this script (eg, if src changes)
pendingScript.onreadystatechange = null;
// can't just appendChild, old IE bug if element isn't closed
firstScript.parentNode.insertBefore(pendingScript, firstScript);
}
}
// loop through our script urls
while (src = scripts.shift()) {
if ('async' in firstScript) { // modern browsers
script = document.createElement('script');
script.async = false;
script.src = src;
document.head.appendChild(script);
}
else if (firstScript.readyState) { // IE<10
// create a script and add it to our todo pile
script = document.createElement('script');
pendingScripts.push(script);
// listen for state changes
script.onreadystatechange = stateChange;
// must set src AFTER adding onreadystatechange listener
// else we’ll miss the loaded event for cached scripts
script.src = src;
}
else { // fall back to defer
document.write('<script src="' + src + '" defer></'+'script>');
}
}
A few tricks and minification later, it’s 362 bytes
!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
"//other-domain.com/1.js",
"2.js"
])
NOTE: there was one similar solution but it doesn't check if the script is already loaded and loads the script each time. This one checks src property and doesn't add script tag if already loaded.
Loader function:
const loadCDN = src =>
new Promise((resolve, reject) => {
if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
const script = document.createElement("script")
script.src = src
script.async = true
document.head.appendChild(script)
script.onload = resolve
script.onerror = reject
})
Usage (async/await):
await loadCDN("https://.../script.js")
Usage (Promise):
loadCDN("https://.../script.js").then(res => {}).catch(err => {})
Dinamically loading JS files is asynchronous, so to ensure your script is loaded before calling some function inside, use the onload event in script:
function loadjs(file) {
var script = document.createElement("script");
script.type = "application/javascript";
script.onload=function(){
//at this tine the script is loaded
console.log("Script loaded!");
console.log(test);
}
script.src = file;
document.body.appendChild(script);
}

Can stripe.js be loaded in non-blocking fashion?

Can stripe.js be deferred and used with some ready - callback that i can't find in the docs?
This is what i wanna do:
<script src="https://js.stripe.com/v2/" async></script>
And then in my app:
function stripeReadyHandler () {
//do stuff
}
Turns out, there's a standards compliant way to do this:
<script src="https://js.stripe.com/v2/" async onload="stripeReadyHandler()"></script>
and then:
function stripeReadyHandler () {
//this will definitely do stuff ( if you're above IE9 of course
}
Or, with JavaScript:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://js.stripe.com/v2/';
document.body.appendChild(script);
script.onload = function() {
Stripe.setPublishableKey(publishableKey);
// do stuff
};

How to include jQuery dynamically in any website using pure javascript

I am trying to include jquery dynamically and i have used the following code-
index.php
<!doctype html>
<html>
<head>
<script type="text/javascript" src="includejquery.js"></script>
</head>
<body>
<div id="testing"></div>
<script type="text/javascript">
$(document).ready(function(){
$('#testing').html('<p>This is a paragraph!</p>');
});
</script>
</body>
</html>
includejquery.js
if(!window.jQuery)
{
var script = document.createElement('script');
script.type = "text/javascript";
script.async = true;
script.src = "http://code.jquery.com/jquery-2.1.1.min.js";
document.getElementsByTagName('head')[0].appendChild(script);
jQuery.noConflict();
}
But jquery functionality is not working it is not printing the paragraph tag :-( Please help me out. Thanks in advance
That's not working because your $(document).ready(... line runs before jQuery loads, and so it fails because either $ is undefined (throwing a ReferenceError) or it refers to something other than jQuery. Also, you're calling jQuery.noConflict() before jQuery is loaded, and if that call did work, it would mean that $ no longer referred to jQuery at all, so $(document).ready(... still wouldn't work.
In any modern browser, you can use the load event on the script element you're adding, which tells you that the script has been loaded. Probably best to pass a callback into a call you make to includejquery.js, like this:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="includejquery.js"></script>
</head>
<body>
<div id="testing"></div>
<script type="text/javascript">
includejQuery(function($){
$('#testing').html('<p>This is a paragraph!</p>');
});
</script>
</body>
</html>
includejquery.js:
function includejQuery(callback) {
if(window.jQuery)
{
// jQuery is already loaded, set up an asynchronous call
// to the callback if any
if (callback)
{
setTimeout(function() {
callback(jQuery);
}, 0);
}
}
else
{
// jQuery not loaded, load it and when it loads call
// noConflict and the callback (if any).
var script = document.createElement('script');
script.onload = function() {
jQuery.noConflict();
if (callback) {
callback(jQuery);
}
};
script.src = "http://code.jquery.com/jquery-2.1.1.min.js";
document.getElementsByTagName('head')[0].appendChild(script);
}
}
Changes there:
In includejquery.js, just define a function and wait to be called.
Have that function accept a callback.
Have it wait for the script to load.
When the script is loaded, call jQuery.noConflict and then, if there's a callback, call it and pass in the jQuery function.
In the HTML, I'm calling the function, and receiving the argument it passes me as $, so within that function only, $ === jQuery even though outside it, it doesn't (because of noConflict).
What's wrong with the implementation from the HTML5-Boilerplate?
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery_2.1.1.min.js"><\/script>')</script>
Alternative solution
(function () {
initScript().then(function (v) {
console.info(v);
var script = document.getElementById("__jquery");
script.onload = function () {
$(document).ready(function () {
// Main logic goes here.
$("body").css("background-color","gray");
});
};
});
function initScript() {
promise = new Promise(function(resolve,reject) {
try {
if(typeof jQuery == 'undefined') {
console.warn("jQuery doesn't exists");
var jQuery_script = document.createElement("script");
jQuery_script.src = "https://code.jquery.com/jquery-2.2.4.min.js";
jQuery_script.type = 'text/javascript';
jQuery_script.id = "__jquery";
document.head.appendChild(jQuery_script);
resolve("jQuery added succesfully.");
}
resolve("jQuery exists.")
} catch (ex) {
reject("Something went wrong on initScript() : ", ex);
}
});
return promise;
}
})();
I used promise because if there is no jQuery in the page we need to wait to load it first.
.ready will not fire since your script loads async.
This should the first thing to run on the page and block all other scripts in order to load the dependencies on time.
Appending to body:
function loadScript() {
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'http://www.mydomain/myscript.js';
script.async = true;
document.body.appendChild(script);
}
Appending to head:
function loadScript() {
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'http://www.mydomain/myscript.js';
script.async = true;
head.appendChild(script);
}
Usually when you include some scripts, browser will load them synchronously, step by step.
But if you set
script.async = true;
script will load asynchronously and other scripts will not waiting for them. To fix this problem you can remove this option.
There is an onload event on the script. Use that.
<!doctype html>
<html>
<head>
<script type="text/javascript">
window.onload = function() {
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "http://code.jquery.com/jquery-2.1.1.min.js";
document.getElementsByTagName('head')[0].appendChild(script);
script.onload = function() {
$('#testing').html('<p>This is a paragraph!</p>');
};
};
</script>
</head>
<body>
<div id="testing"></div>
</body>
</html>
Check your browsers js console. You will probably see something like $ is undefined and not a function. It is because you are running the code in
You can try to wrap the jquery code you want to run in the readyStateChange event of the script tag. Or you can use require.js.
There is a working demo http://jsbin.com/lepapu/2/edit (Click "Run with JS")
<script>
if(!window.jQuery)
{document.write('<script src=http://code.jquery.com/jquery-2.1.1.min.js><\/script>')}
</script>
<script>
$(document).ready(function(){
$('body').html('<p>This is a paragraph!</p>');
});
</script>
The order of scripts matters.

Categories