Suppose that I want to publish a JavaScript library. There is one problem, though: certain features of this library depend on another library, which is located in a permanent url. Instead of expecting my users to include the dependency, I want to automate this. My question is: what is the most elegant/short way to load such dependency from bare JavaScript?
In other words, I need a short, cross-browser implementation of the "load" function bellow:
MyLib = (function(){
var locals = blabla;
load("http://foo.com/lib.js", function(){
// Library loaded! I can use it here.
...
});
return {...};
})();
Note this can not depend on any other external library (such as requirejs) since such dependency would beat the purpose by definition. After all, it would just force my user to add that dependency instead anyway!
Something like this should do what you want cross-browser
function load(url, callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onreadystatechange = callback;
script.onload = callback;
head.appendChild(script);
}
Use Requirejs for that case:
require(["http://foo.com/lib.js"], function (lib) {
});
More info: http://requirejs.org/docs/start.html , https://egghead.io/lessons/requirejs-introduction-to-requirejs
Related
I want to add a element into the existing DOM to have the javascript code run.
I did this with YUI:
var scriptNode = Y.Node.create('<script type="text/javascript" charset="utf-8">alert("Hello world!");<\/script>');
var headNode = Y.one('head');
headNode.append(scriptNode);
It's successfully added to the DOM but it doesn't give me an alert.
Someone knows what the problem is?
I have no idea how YUI's Node.create() function works, so no comment on that. But a simple cross-browser script is:
window.onload = function() {
var s = document.createElement('script');
s.type = 'text/javascript';
var code = 'alert("hello world!");';
try {
s.appendChild(document.createTextNode(code));
document.body.appendChild(s);
} catch (e) {
s.text = code;
document.body.appendChild(s);
}
}
The try..catch block is necessary as most browsers like the first method but some don't and throw an error. The second method covers those. You can also simply eval the code, which is more or less equivalent and what some libraries do.
I found this function in the JQuery source, which seems to do what you want and feels a bit cleaner than the other approaches to me. But then again I am a JS beginner and probably don't see the details. Anyways, somebody might take something useful away from this.
function DOMEval( code, doc ) {
doc = doc || document;
var script = doc.createElement( "script" );
script.text = code;
doc.head.appendChild( script ).parentNode.removeChild( script );
}
I need to include multiple js files in synchronous manner and once they are successfully included I will call function main() which will create the widget. For that currently I have built a function this way
var scriptArrayHC = [retrieveURL()+"/js/bootstrap.min.js",
"//platform.twitter.com/widgets.js",
retrieveURL()+"/js/html5shiv-2.js",
retrieveURL()+"/js/ie-emulation-modes-warning.js",
retrieveURL()+"/js/ie10-viewport-bug-workaround.js"];
function loadScript(scriptArray, func){
var counter_script=0;
[].forEach.call(scriptArray, function(src){
var script = document.createElement('script');
script.onload = function() {
counter_script++;
//console.log("Script "+counter_script+" --- "+src);
if(counter_script==scriptArray.length) eval(func);
};
script.src = src;
document.getElementsByTagName('head')[0].appendChild(script);
});
}
loadScript(scriptArray, "main()");
It is working fine.. But i think it is not the best way. Does anyone have a better way to do this or is there any library for this?
USE RequireJS to solve the issue
I am quite new to javascript and I am struggling with a simple problem. I have to split up codes into separate files. As an example I have a file called Database.js. In that file I have the following lines:
function Database(){
//someStuff
this.fetchAll = function(){
//some stuff
return something;
}
}
Now I want to use the Database.js code in the file app.js. So I write the following code in app.js:
var Database = require('Database');
var myDB = new Database();
var result = myDB.fetchAll();
However, I get the error Script Error = '[object Database]' is not a constructor (evaluating 'new Database()') at app.js (line 3).
What is my mistake?
Before you moving to the development, you need to understand thoroughly about CommonJS Modules in Titanium. Then it will be more simple for you. Also refer the require function
Let's come to your error. [ERROR] [object Database]' is not a constructor (evaluating 'new Database()') at app.js (line 3) means that the module you created is not constructor. Your constructor function might not return any value. Read simple usage of CommonJS module. I'm sure it will resolve your issue.
There is an alternative way, you can include your Database.js file in your app.js. You does not need to return anything and no need to use require function. You just need to use the include method. Just write Ti.include('Database.js'); inside your app.js and you can access all the global variables and functions inside the Database.js file
This question is old but it has not been answered yet. So i will just provide the answer for anyone who is visiting here.
You have to export you function as global. To do so you would declare it as below
exports.fetchAll = function Database(){
//some stuff
return something;
};
You can also declare the function so that it can be used globally as well as locally within the file
var fetchAll = function Database(){
//some stuff
return something;
};
exports.fetchAll = fetchAll;
Then assuming the file name is Database and it is in same folder as app.js, you can use it as below
var Database = require('Database');
var result = Database.fetchAll();
edit: This answer is javascript general and it's not oriented towards Appacelerator Titanium.
There is no such include or require in javascript. You can on the other hand do one of the following
Include a script tag before your script to include Database.js
<script type="text/javascript" src="Database.js" >
OR
Add it dynamically
function loadScript(url, callback)
{
// adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// then bind the event to the callback function
// there are several events for cross browser compatibility
script.onreadystatechange = callback;
script.onload = callback;
// fire the loading
head.appendChild(script);
}
The problem seemed to be the usage of the variable name 'Database'. Maybe there is somewhere a name collusion.
I am sorry that I did not know that the usage of require is not a basic concept of js.
Just a quick guess here. If you use CommonJS then you have to tell what should be available outside of the module. The way you lay out that you have made the Database "object" you would need to add:
module.exports = Database;
somewhere in your module. I always put them at the end - but not sure that is a requirement.
You can also make individual functions available outside of a module by specifying:
exports.getMyDatabase = getMyDatabase;
Where "getMyDatabase" is a function you have specified in the module. I use this way to "hide" certain implementation details of some functions from the outside and just make available the functions I want the developer to be able to call ;-)
/John
I think this is the right usage of require js:
require(["Database"], function() {
var myDB = new Database();
var result = myDB.fetchAll();
});
http://requirejs.org/docs/jquery.html
Let's say I have some simple Javascript like:
<script>
var hello = function(){
alert("Hello World!");
}
</script>
.. on a page helloworld.html. If I loaded this script block into another page using Pjax. How do I execute the function hello()?
For security reasons, many browsers will not run Javascript injected by innerHTML, which I'm thinking Pjax likely uses. (Here's a minimal example.)
Maybe the solution proposed in Pjax's issue #48 will help
What worked for me was to place my jQuery code in a function, call it
normally on document.ready (for non-pushState browsers), and then bind
the function to pjax:end, i.e.:
$('body').bind 'pjax:end', mainFunction
This is possible with PJAX. You just need to have the script tag with type text/javascript.
Code from PJAX library:
function executeScriptTags(scripts) {
if (!scripts) return
var existingScripts = $('script[src]')
scripts.each(function() {
var src = this.src
var matchedScripts = existingScripts.filter(function() {
return this.src === src
})
if (matchedScripts.length) {
matchedScripts.remove();
}
console.error("FOUND SCRIPTS", scripts, matchedScripts.length);
var script = document.createElement('script')
script.type = $(this).attr('type')
script.src = $(this).attr('src')
document.head.appendChild(script)
})
}
I'm using a fairly simple system to load javascript dynamically:
include = function (url) {
var e = document.createElement("script");
e.src = url;
e.type="text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
};
Let's say I have a file test.js which has the following contents:
var foo = 4;
Now, in my original script, I want to use
include(test.js);
console.log(foo);
However, I get a 'foo has not been defined' error on this. I'm guessing it has to do with the dynamic script being included as the last child of the <head> tag. How can I get this to work?
It is because you have to wait for the script to load. It is not synchronous like you would think. This may work for you:
include = function (url, fn) {
var e = document.createElement("script");
e.onload = fn;
e.src = url;
e.async=true;
document.getElementsByTagName("head")[0].appendChild(e);
};
include("test.js",function(){
console.log(foo);
});
That is one problem, but it also takes time for the browser to download and parse the remote JS file — and it hasn't done that before you call console.log.
You need to delay things until the script has loaded.
This is easiest done by letting a library do the heavy lifting, jQuery has a getScript method that lets you pass a callback to run when the script has loaded.