javascript linking - javascript

I'm going to build a rather complicated application in html5 with some heavy javascripting.
In this I need to make some objects which can be pass around. But since there is no like #import foobar.js.
Then I assume that if my html page loads the scripts, then all the scripts can access eachother?
I read (here) that ajax somehow is able to load a .js file from within another .js file. But i dont think this is what I need?
Can go more into details if needed, thanks in advance.

In our projects, we do the following: Suppose you're going to call your project Foo, and have a module called Bar in it,
Then what we do is declare a file called Foo.js that just defines an equivalent to a Foo namespace:
Foo = (function(){
return {
};
})();
Then we create a file called Foo.Bar.js that contains the code for the Bar module:
Foo.Bar = (function(){
// var declarations here that should be invisible outside Foo.Bar
var p, q;
return {
fun1 : function(a, b){
// Code for fun1 here
},
fun2 : function(c) {
// Code for fun2 here
}
} // return
})();
Note that how it is a function that executes immediately, and returns an object that gets assigned to Foo.Bar. Any local variables, like p and q are available to fun1 and fun2 because they're in a closure, but they are invisible outside of Foo.Bar
The functions in Foo.Bar can be constructors for objects and so on.
Now in your HTML you simple include both files like so:
<script type="text/javascript" src="Foo.js"></script>
<script type="text/javascript" src="Foo.Bar.js"></script>
The result will be that you can call Foo.Bar's functions in the JavaScript of your main HTML file without any problems.

You should check out the module pattern:
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth/
This describes alternatives for creating modular code in javascript, how you can protect your code and share APIs and data among them.
You should also consider using and AMD. Require.js is quite popular, but I tend to prefer head.js for this. Keep in mind that these put some requirements on how you structur your code in files, and personally, I don't think it's worth it, compared to a concatenated and minified file included in the bottom of the page.

Then I assume that if my html page loads the scripts, then all the scripts can access eachother?
Yes.

Related

How can you capture the result of a HTML script tag in a variable?

I have been reading about AMD and implementations like requirejs. Most of the resources covers the usage and API's.
But, when it comes to implementing this, how can you load a JavaScript file into a variable just like that? For example, you can see functions like this:
define(['jquery'], function($){
});
var jquery = require('./jquery');
From an API consumer's perspective, all I can understand is that the file jquery.jshas magically become $, jQuery etc? How is that achieved?
Any examples would be helpful.
How do AMD loaders work under the hood? is a helpful read.
Edit: I think the eval answers below are nice because it actually is an eval problem in some ways. But I would like to know this from the perspective of an AMD specs implementation.
You don't load a javascript file into a variable, this is instead done by things such as browserify or webpack. Javascript itself can do this, but these modules generate a single file containing all your code. By calling require("file"), you are calling browserify's function to load a file named "file" stored in the code.
An example of this can be if you have a module
function demoModule(){
console.log("It works!");
}
module.exports = demoModule
This makes module.exports now contain the "entire" contents of the file
Browserify/webpack puts that into a function that returns the module.exports of that file
function require(filename) {
switch(filename){
case "demofile":
let module = {exports:{}}; ((module) => {
function demoModule(){
console.log("It works!");
}
module.exports = demoModule
})(module)
return module.exports;
}
};
require("demofile")();
Your file becomes a function that you can call with require("demofile") and it returns anything that was a module.export.
You know how you can say eval(alert("hello!")) and it executes the code?
You can also:
var str = "hello!"
eval('alert("' + str + '");')
So the next step is to have a file that has your actual script in it:
var str = "hello"
alert(str)
then you can use a standard AJAX request to fetch that file into a variable, and you can eval() that variable.
Technically, eval() is considered evil - fraught with dangers - but there are other solutions (for example, injecting a script tag into the document body). I just went with eval() here to make the explanation easier.
Extending what theGleep said.
Something like this:
var str = "if (x == 5) {console.log('z is 42'); z = 42;} else z = 0;";
console.log('z is ', eval(str));
For more read here.
But use eval() very cautiously and be absolutely sure about the pitfalls and drawbacks of eval().
Don't use it unless it is the only option.
Read this answer too.
The way define works under the hood is not by loading an "HTML Script into a variable". Typically a normal script can have multiple variables so it doesn't make sense to capture the value a variable! The eval approaches can probably do something like that if needed. It captures all that is there in the JavaScript source code.
The real key in AMD is that the define API maps a name to a function. Whenever you require with that name, it would just call that function and return the value to you. This return value is expected to be the module. This is a convention that makes everything work!
In other words, AMD uses an interesting convention (design pattern) to ensure that we get a modularization effect in JavaScript code. It is one level of indirection. Instead of the normal style of "write your code and get it executed in the global scope" paradigm, you just write a function that returns a single value that captures all the things you want to expose as a module to the consumer!

Accessing variables and methods from another file

In this case, How do I access the variable and method declared in a file from another file?
File one
jQuery(function(t) {
var myVar = 'myValue',
e = function(t) {
console.log('myLog');
}
});
File two
jQuery(function($){
// ????
});
You don't. It has nothing to do with files (JavaScript largely doesn't care about files unless they're ES2015+ modules), it has to do with the fact that both myVar and e are entirely private to the anonymous function you're passing into jQuery in the first code block. Even other code outside that function in the same file would be unable to access them.
You'd have to change the first file to make that information accessible outside that function. You could do that by making them globals (blech), or by having a single global you use for all of your things like this with an object with properties for these things (slightly less "blech" :-) ), or by using something like Webpack and true modules.
It really depends on how you setup your scripts. For instance:
<script src="fileOne.js"></script>
<script src="fileTwo.js"></script>
Then you will be able to do the following:
File One:
- Declare variable x
File Two:
- Access variable x
I recommend taking a look at this, it'll help with understanding variable scope (however this doesn't cover ES6's let): https://www.w3schools.com/js/js_scope.asp

How to use function declared in different JS file using jQuery getScript?

I have two JS files. One is called common.js and it use $.getScript to include other file with my js code. Part of including looks like this:
jQuery.getScript(js_path + "table.js", function(){
generateTable(chartData, dataTypes);
});
This file (common.js) also contains function compare(a, b).
Now, the second one (table.js) has declared different function which uses the compare function from the first file. Something like this:
function someName() {
var a = 2,
b = 5;
var test = compare(a, b);
return test;
}
When I run the code it gives me:
Uncaught ReferenceError: compare is not defined
How can I use function from the first file.
jQuery.getScript first fetches the JS file from the server, then executes it. If you want to work with global functions (as it seems) you need to pay attention to the following:
Your compare function must be declared before the table.js file is executed.
The compare function must be declared on the global namespace of table.js.
Sorry but without more info this is all you can get.
If your main file, as something like:
(function() {
function compare(){...}
}());
Then the compare function is not declared in the global namespace.
did you check the order of imports? The file with 'compare' method should be first. It should solve the problem.
What I would suggest is to skip getScript if it's just for separating the code.
<script src="common.js"></script>
<script src="table.js"></script>
<script src="app.js"></script>
Where common functions go into common, your table stuff goes into table. This way you get the ordering right. This also clears out the circular dependency one might see a hint of if table depends on common that depends on table by extracting all but the 'common' parts into some form of 'app'.

Dojo module loading in general

Coming from Java/C# I struggle to understand what that actually means for me as a developer (I'm thinking too much object-oriented).
Suppose there are two html files that use the same Dojo module via require() in a script tag like so:
<script type="text/javascript">
require(["some/module"],
function(someModule) {
...
}
);
</script>
I understand that require() loads all the given modules before calling the callback method. But, is the module loaded for each and every require() where it is defined? So in the sample above is some/module loaded once and then shared between the two HTMLs or is it loaded twice (i.e. loaded for every require where it is listed in the requirements list)?
If the module is loaded only once, can I share information between the two callbacks then? In case it is loaded twice, how can I share information between those two callbacks then?
The official documentation says "The global function define allows you to register a module with the loader. ". Does that mean that defines are something like static classes/methods?
If you load the module twice in the same window, it will only load the module once and return the same object when you request it a second time.
So, if you're having two seperate pages, then it will have two windows which will mean that it will load the module two times. If you want to share information, you will have to store it somewhere (the web is stateless), you could use a back-end service + database, or you could use the HTML5 localStorage API or the IndexedDB (for example).
If you don't want that, you can always use single page applications. This means that you will load multiple pages in one window using JavaScript (asynchronous pages).
About your last question... with define() you define modules. A module can be a simple object (which would be similar to static classes since you don't have to instantiate), but a module can also be a prototype, which means you will be able to create instances, for example:
define([], function() {
return {
"foo": function() {
console.log("bar");
}
};
});
This will return the same single object every time you need it. You can see it as a static class or a singleton. If you require it twice, then it will return the same object.
However, you could also write something like this:
define([], function() {
return function() {
this.foo = function() {
console.log("bar");
};
};
});
Which means that you're returning a prototype. Using it requires you to instantiate it, for example:
require(["my/Module"], function(Module) {
new Module().foo();
});
Prototyping is a basic feature of JavaScript, but in Dojo there's a module that does that for you, called dojo/_base/declare. You will often see things like this:
define(["dojo/_base/declare"], function(declare) {
return declare([], {
foo: function() {
console.log("bar");
}
});
});
In this case, you will have to load it similarly to a prototype (using the new keyword).
You can find a demo of all this on Plunker.
You might ask, how can you tell the difference between a singleton/static class module, and a prototypal module... well, there's a common naming convention to it. When your module starts with a capital letter (for example dijit/layout/ContentPane, dojo/dnd/Moveable, ...) then it usually means the module requires instances. When the module starts with a lowercase letter, it's a static class/singleton (for example dojo/_base/declare, dijit/registry)
1) dojo require, loads the module once and then if you called it again require() will simply return if the package is already loaded. so the request will be called once and it will also call any dependencies once.
but all that if you are in the same HTML page if you leave the page and call the same module in a different page then it will be called from the server. you can also use cache in your config settings so things will be cached in the browser and the file will or not by setting the cacheBust to true if you want a fresh copy or false if you want things to be cached.
2) if you are in the same html page and domain, the module didn't change the module will be the same and you can share values and any change you make you can get it from anywhere unless you call a new instance. but that is not possible between different html pages.
3) not it is not like a static classes or methods from what I understand static methods A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields..
dojo work differently it is a reference for an object if you did it in that way :
define(function(){
var privateValue = 0;
return {
increment: function(){
privateValue++;
},
decrement: function(){
privateValue--;
},
getValue: function(){
return privateValue;
}
};
});
This means every bit of code loads that module will reference the same object in memory so the value will be the same through out the use of that module.
of course that is my understanding please feel free to tell me where I am wrong.

calling a javascript function from a separate script?

I want to organize my JavaScript so I thought I would make a functions JS file. Is there anyway I can call the functions from functions.js from global.js?
EDIT
functions.js:
var get_selects;
get_selects = {
getLanguages: function() {
}
}
global.js:
get_selects.getLangueges();
Yes, functions defined at the top level are automatically available in the global scope (window in a browser), and this is typically not desirable.
Another approach that would mitigate this is to group your functions into a single object so you aren't polluting the global scope with a whole bunch of unrelated functions.
var utils;
utils = {
toast: function(message) {
alert("Notification: " + message);
},
sum: function(a, b){ return a + b; }
}
utils.toast('Email sent');
utils.sum(1, 2);
If both scripts have been included in the same HTML file, sure, it will work out of the box. Best way to know is to try it.
All .js files load top level functions into the global namespace. So, yes.
simply call it like anyother functions
yourFunctionName(yourFunctionParams);
be aware, you need to include your functions.js BEFORE your global.js, else it won't see your functions.
From the moment you include a JS in the HTML file, all the functions become available. So, if you make like this, it will work:
<script type="text/javascript" src="functions.js"></script>
<script type="text/javascript" src="global.js"></script>
But (as soon as I know), you must include "functions.js" first. Otherwise, "global.js" will not be able to find the calls. You can also make a little function inside "global.js" to include "functions.js" on the fly, like this:
function include(js_path){
//By Fabrício Magri e Micox
//http://elmicox.blogspot.com/2006/12/include-em-javascript.html
var new= document.createElement('script');
new.setAttribute('type', 'text/javascript');
new.setAttribute('src', js_path);
document.getElementsByTagName('head')[0].appendChild(new);
}
Than, on the beginning of your "global.js" you call this function to include the contents of "functions.js" on the section as soon as the browser requests "global.js"

Categories

Resources