in my script below, I use javascript to load jquery dynamically first. Once loaded, I want to namespace jquery's $ so that I may use another name for it throughout my site. For instance, instead of calling $('body'). , I want to call MYNAMESPACE('body'). But I can't get the namaspacing done correctly. Please help me on that part. Thanks..
(function () {
function loadScript(url, callback) {
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState) { //IE
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function () {
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("/plugins/system/conversekit/js/jquery.js", function () {
//jQuery loaded
alert('jquery loaded');
var cKit = (function($){
var loadScripts = function(){
var jq = $.noConflict();
return jq;
}
return {
ConversekitJs : loadScripts// I expect this to return namespaced jquery
};
}
})(jQuery);
var js = cKit.ConversekitJs(); //function call
//so that I may use jq instead of $ or jQuery
js('body').css('background-color', '#ff0000');
});
})();
EDIT based on answer suggested by R.J:
var myNameSpace = jQuery.noConflict();
(function(myNameSpace) {
//Use your namespace
myNameSpace('body').css('background-color', '#ff0000');//works
myNameSpace.getScript("/js/events.js");//in this file myNameSpace has no effect..
})(myNameSpace)
In events.js
myNameSpace('body').css('background-color', '#ff0000');//doesn't work
But if I add var myNameSpace = jQuery.noConflict(); on top of the page it would work..This is what I want to avoid. Instead of declaring this in each page, I would like to define once in top level.
You can use jQuery.noConflict with IIFE
var myNameSpace = jQuery.noConflict();
(function(myNameSpace) {
//Use your namespace
myNameSpace('body').css('background-color', '#ff0000');
})(myNameSpace)
It is possible, but you would have to edit the jQuery source code somewhat.
/*!
* jQuery library
*/
( function( global, factory ) {
...
})(window);
var myNamespace = myNamespace || {};
myNamespace.$ = myNamespace.jQuery = jQuery.noConflict(true);
This should give you the jquery function or the $ shortcut under your own namespace.
Related
I have 4 javascript libraries I would like to load if the are not already loaded. Then, I want to use their functions.
My problem is that I am getting Uncaught ReferenceError: sbjs is not defined, the scripts get loaded but I can't actually use them.
I have it working perfectly to where it will add the scripts above the </body> tag if they are not already loaded, but I can't seem to get them to work.
Here is my code:
<script>
window.onload = myapp_scripts;
function myapp_scripts () {
var myapp_script;
if (!window.jQuery) {
myapp_script = document.createElement('script');
document.body.appendChild(myapp_script);
myapp_script.src = 'http://myapp.dev/js/jquery.min.js';
console.log('load jquery');
}
if (!window.Cookies) {
myapp_script = document.createElement('script');
document.body.appendChild(myapp_script);
myapp_script.src = 'http://myapp.dev/js/cookie.min.js';
console.log('load cookies');
}
if (typeof url == 'undefined') {
myapp_script = document.createElement('script');
document.body.appendChild(myapp_script);
myapp_script.src = 'http://myapp.dev/js/url.min.js';
console.log('load url');
}
if (typeof sbjs == 'undefined') {
myapp_script = document.createElement('script');
document.body.appendChild(myapp_script);
myapp_script.src = 'http://myapp.dev/js/sourcebuster.min.js';
console.log('load sbjs');
}
myapp_init();
}
function myapp_init () {
sbjs.init();
console.log(Cookies.get('source_id'));
console.log(url('source_id'));
console.log(sbjs.get.current);
$('#myapp_form').submit(function (event) {
event.preventDefault();
console.log('form submitted');
});
}
</script>
How do I make it so I can also use the scripts I've loaded dynamically?
I think your problem is because myapp_init() is executed before scripts are loaded
You need to manage script load event and after call myapp_init()
some like this inside each if() condition:
var myapp_script;
var scripts_loaded = 0;
if (!window.jQuery) {
myapp_script = document.createElement('script');
document.body.appendChild(myapp_script);
myapp_script.src = 'http://myapp.dev/js/jquery.min.js';
console.log('load jquery');
myapp_script.onload = function(){
scripts_loaded ++;
if(scripts_loaded === 4){ //4 because in your example you have 4 scripts to load
myapp_init();
}
}
}else{
scripts_loaded ++;
}
//...
//And so on with others if conditions
Is not a elegant solution but is only one the idea: to check in some way if all scripts are loaded and after that call myapp_init();
I have this script
<script>
function loadJS(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
var state = s.readyState;
if (!callback.done && (!state || /loaded|complete/.test(state))) {
callback.done = true;
callback();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
loadJS('/script/script.js', function() {
// put your code here to run after script is loaded
});
</script>
And I can't figure out how can I get response data from the script I'm trying to load.
Basically, this script contains a function that does something and then returns some value.
I know that in jQuery analog in would be just data argument in getScript function, but I only have native JS here.
What and where should I add to get response data in my script?
Assuming that your script contains a function declared in a global scope, you can simply include this script and then execute any function / access any member from this script:
After your script has been loaded and executed, you can work with it just like with a simple script which is a part of your current document.
Here is a demo which loads jQuery script from Google CDN and then outputs jQuery version (which is a part of jQuery library):
function loadJS(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
var state = s.readyState;
if (!callback.done && (!state || /loaded|complete/.test(state))) {
callback.done = true;
callback();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
console.log("typeof jQuery: " + typeof jQuery); // jQuery not loaded
loadJS("https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js", function() {
console.log("typeof jQuery: " + typeof jQuery + ", version = " + jQuery.fn.jquery); // jQuery has been loaded
});
I'm appending into my page multiple scripts including jQuery, jQuery migrate... all from same .js file
this is how it looks:
function appendScript(pathToScript, run) {
var head = document.getElementsByTagName("head")[0];
var js = document.createElement("script");
js.type = "text/javascript";
if(run == true){
js.onreadystatechange = function () {
if (this.readyState == 'complete') runFunctions();
}
js.onload = runFunctions;
}
js.src = pathToScript;
head.appendChild(js);
}
appendScript("http://code.jquery.com/jquery-latest.min.js");
appendScript("http://code.jquery.com/jquery-migrate-1.3.0.min.js", true);
function runFunctions(){
console.log('test') // all good till here
// here i have only jquery functions
$('#myDiv').addClass('test');
alert("this doesn't work");
....
}
My problem is that I can't run $(document).ready or any jQuery function, only javascript.
Tried with timeout too. Also I already have 1 x $(window).bind("load", function(){...} so I don't need 1 more
Since jQuery Migrate depends on jQuery, you need to wait until loading the next script.
Here is a working example (I also cleaned up some variables).
function appendScript(src, callback) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
if (callback) {
script.onload = callback;
}
script.src = src;
head.appendChild(script);
}
appendScript("https://code.jquery.com/jquery-latest.min.js", function() {
appendScript("https://code.jquery.com/jquery-migrate-1.3.0.min.js", function() {
document.body.innerHTML = 'Loaded jQuery version ' + jQuery.fn.jquery;
});
});
See working jsfiddle.
I have a widget that only works with one instance.
The problem I have is that if I have one instance of the widget on a page it works fine. If I have more than one instance on the page, only one instance works. The second instance does not work...
you can check this page for an example http://fullylinked.com/advert.php
From my troubleshooting, I have noticed the following
1. The placement ID of the second instance is not passed to the script.
2. Even if the default placement ID is used, I get an error saying
"Uncaught ReferenceError: jsonpCallback is not defined".
Unfortunately the jsonpCalback is defined because the first script works..
Please here are my code..
The Widget...
<script placementID = "37" src="placement.js" type="text/javascript"> </script>
<div id="widget-container_37"></div>
---- Second instance below this line -------
<script placementID = "36" src="placement.js" type="text/javascript"></script><div id="widget-container_36"></div>
NOW HERE IS THE .JS file
(function() {
// Localize jQuery variable
var jQuery;
/******** Load jQuery if not present *********/
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.4.2') {
var script_tag = document.createElement('script');
script_tag.setAttribute("type","text/javascript");
script_tag.setAttribute("src",
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
if (script_tag.readyState) {
script_tag.onreadystatechange = function () { // For old versions of IE
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
} else {
script_tag.onload = scriptLoadHandler;
}
// Try to find the head, otherwise default to the documentElement
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} else {
// The jQuery version on the window is the one we want to use
jQuery = window.jQuery;
main();
}
/******** Called once jQuery has loaded ******/
function scriptLoadHandler() {
// Restore $ and window.jQuery to their previous values and store the
// new jQuery in our local jQuery variable
jQuery = window.jQuery.noConflict(true);
// Call our main function
main();
}
/******** Our main function ********/
function main() {
jQuery(document).ready(function($) {
/******* Load CSS *******/
/** var css_link = $("<link>", {
rel: "stylesheet",
type: "text/css",
href: "style.css"
});
css_link.appendTo('head');
/**** get host name ***/
var site_name = window.location.hostname;
/****** get user ID******/
var this_js_script = $('script[src*=placement]'); // get file name..*/
var placementID = this_js_script.attr('placementID');
/**var placementID = document.getElementById("adblabla_2").getAttribute("placementID");**/
if (typeof placementID === "undefined" ) {
var placementID = '23';
}
/******* Load HTML *******/
$.ajax({
url: 'processors/processor.php?placementID='+placementID,
data: {name: 'Chad', site: site_name},
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(data){
//alert(placementID);
$('#widget-container_'+placementID).html(data.message);
}
});
});
function jsonpCallback(data){
$('#widget-container_2').text(data.message);
}
}
})();
The reason is another then I thought, your code is already encapsulated, so its not calling twice the same main function, but it finds twice the same script tag, and thus gets the wrong parameter I think.
http://www.2ality.com/2014/05/current-script.html
Well you can try this code:
(function () {
// Localize jQuery variable
var jQuery,
//get current script
currentScript = document.currentScript || (function () {
var scripts = document.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
/******** Load jQuery if not present *********/
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.4.2') {
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src",
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
if (script_tag.readyState) {
script_tag.onreadystatechange = function () { // For old versions of IE
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
} else {
script_tag.onload = scriptLoadHandler;
}
// Try to find the head, otherwise default to the documentElement
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} else {
// The jQuery version on the window is the one we want to use
jQuery = window.jQuery;
main();
}
/******** Called once jQuery has loaded ******/
function scriptLoadHandler() {
// Restore $ and window.jQuery to their previous values and store the
// new jQuery in our local jQuery variable
jQuery = window.jQuery.noConflict(true);
// Call our main function
main();
}
/******** Our main function ********/
function main() {
jQuery(document).ready(function ($) {
/******* Load CSS *******/
/** var css_link = $("<link>", {
rel: "stylesheet",
type: "text/css",
href: "style.css"
});
css_link.appendTo('head');
/**** get host name ***/
var site_name = window.location.hostname;
/****** get user ID******/
var this_js_script = $(currentScript); // get file name..*/
var placementID = this_js_script.attr('placementID');
/**var placementID = document.getElementById("adblabla_2").getAttribute("placementID");**/
if (typeof placementID === "undefined") {
var placementID = '23';
}
/******* Load HTML *******/
$.ajax({
url: 'processors/processor.php?placementID=' + placementID,
data: {name: 'Chad', site: site_name},
dataType: 'jsonp',
jsonp: 'callback',
success: function (data) {
//alert(placementID);
$('#widget-container_' + placementID).html(data.message);
}
});
});
function jsonpCallback(data) {
$('#widget-container_2').text(data.message);
}
}
})();
PS: its always very useful when you build up a testcase on http://jsfiddle.net/
I have some javascript code which detects whether the useragent is an android, iphone or ipod and then only loads my javascript files if this is the case.
The following code works perfectly but I am aware that I do not need to have two 'createscript' functions (with different names) that do the same thing so I am trying to use a parameter/variable instead. I've tried everything i can think of but it's not working.
<script type="text/javascript">
if(navigator.userAgent.match(/Android/i) ||
navigator.userAgent.match(/webOS/i) ||
navigator.userAgent.match(/iPhone/i) ||
navigator.userAgent.match(/iPod/i)) {
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function createScript()
{
var oNode=document.createElement("script");
document.getElementsByTagName("body")[0].appendChild(oNode);
oNode.setAttribute("id", "newScript", 0);
oNode.setAttribute("type", "text/javascript", 0);
oNode.setAttribute("src", "nav.js", 0);
}
function createScript_()
{
var oNode=document.createElement("script");
document.getElementsByTagName("body")[0].appendChild(oNode);
oNode.setAttribute("id", "newScript", 0);
oNode.setAttribute("type", "text/javascript", 0);
oNode.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js", 0);
}
addLoadEvent(createScript);
addLoadEvent(createScript_);
}
</script>
And here is the new code with parameters that I have been trying out (its the same as above accept I've set a parameter for the createscript function) But it doesnt work:
<script type="text/javascript">
if(navigator.userAgent.match(/Android/i) ||
navigator.userAgent.match(/webOS/i) ||
navigator.userAgent.match(/iPhone/i) ||
navigator.userAgent.match(/iPod/i)) {
alert("This is a mobile device");
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function createScript(scriptname)
{
var oNode=document.createElement("script");
document.getElementsByTagName("body")[0].appendChild(oNode);
oNode.setAttribute("id", "newScript", 0);
oNode.setAttribute("type", "text/javascript", 0);
oNode.setAttribute("src", + scriptname + , 0);
}
createscriptlibrary = createScript("https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js");
createmyscript = createScript("nav.js");
addLoadEvent(createscriptlibrary);
addLoadEvent(createmyscript);
}
</script>
It's probably something small but I can't figure it out. Thanks for your help.
Edit:
Thanks to #t-j-crowder I have edited my code as follows and this works perfect:
<script type="text/javascript">
if(navigator.userAgent.match(/Android/i) ||
navigator.userAgent.match(/webOS/i) ||
navigator.userAgent.match(/iPhone/i) ||
navigator.userAgent.match(/iPod/i)) {
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function createscript(scriptName) {
var oNode = document.createElement('script');
oNode.src = scriptName;
document.body.appendChild(oNode);
}
addLoadEvent(createscript.bind(undefined, "https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"));
addLoadEvent(createscript.bind(undefined, "nav.js"));
}
</script>
There are still some issues with this code as #t-j-crowder pointed out about the fact that I cannot rely on my two .js files loading in the right order so I will try out the guard as he suggested below in his answer. Thanks for all the comments.
New edit to question-loading in a css file:
I now have the following code which loads my jquery lib and nav2.js file when the page is loaded. This works perfect. I am trying to get my code to load a css file dynamically when the browser supports javascript but it is not working. Can anybody see why? is it because the page is displaying before the css file is loaded? Here is my script code:
<script type="text/javascript">
function loadcssfile(filename){
var fileref=document.createElement("link");
fileref.href = filename;
document.getElementsByTagName("head")[0].appendChild(fileref);
}
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function createscript(scriptName) {
var oNode = document.createElement('script');
oNode.src = scriptName;
document.body.appendChild(oNode);
}
addLoadEvent(createscript.bind(undefined, "https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"));
addLoadEvent(createscript.bind(undefined, "nav2.js"));
loadcssfile("jqueryjava.css");
</script>
The reason that doesn't work is that createScript doesn't return a function, but you're expecting it to.
The simplest way is just to do this:
addLoadEvent(function() { createscript("https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"); });
addLoadEvent(function() { createScript("nav.js"); });
Note, though, that you're giving the same id value to each script tag created by createScript, which isn't valid.
In an ES5-enabled environment, you could use Function#bind, but something about your question suggests to me you can't rely on being in an ES5-enabled environment. But for completeness:
addLoadEvent(createscript.bind(undefined, "https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"));
addLoadEvent(createScript.bind(undefined, "nav.js"));
Actually, no, the simplest way is to use any of several libraries designed for this, like RequireJS. :-)
Side note: Your createScript function can be markedly simpler (and in fact, the one you've quoted in your question has a syntax error as of the + before scriptName):
function createScript(scriptName) {
var oNode = document.createElement('script');
oNode.src = scriptName;
document.body.appendChild(oNode);
}
There's no need to set type, and you don't want to set id unless you're also passing in an id for each script. And both src and type are reflected properties, no need to use setAttribute on them.
And a final side note: Your nav.js cannot rely on jQuery already being loaded if you load the scripts this way. nav.js can be retrieved and evaluated (run) before jQuery is, even though you're creating the jQuery script element first. Scripts added dynamically are not necessarily evaluated in order. So you need a guard on your nav.js code, like:
(function() {
check();
function check() {
if (typeof jQuery === "undefined") {
setTimeout(check, 50);
}
else {
init();
}
}
function init() {
}
})();
That will check for jQuery and wait 50ms if it doesn't find it (and keep doing that forever, you might want a master timeout).
In my latest edit above I was wondering how to add a css file dynamically.
I have used the following code instead and it is now working. Thanks
<script type="text/javascript">
var headID = document.getElementsByTagName("head")[0];
var cssNode = document.createElement('link');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.href = 'jqueryjava.css';
headID.appendChild(cssNode);
</script>