dojo - declare function - javascript

I can't seem to get the dojo example about declare to work. Example link : http://dojotoolkit.org/reference-guide/1.9/dojo/_base/declare.html#id3
Here is how I set it up:
/index.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js" data-dojo-config="async: true"></script>
<script src="/my/Employee.js"></script>
<script src="/my/Person.js"></script>
<script>
var dojoConfig = {
parseOnLoad: true,
packages: [{
"name": "my",
"location": location.pathname.replace(/\/[^/]+$/, "") + "/my"
}
]
};
</script>
<script>
require(["my/Person"], function (Person)
{
var folk = new Person("phiggins", 42, "Tennessee");
});
require(['my/Employee'], function (Employee)
{
var matt = new Employee("Matt", 33, "California", 1000);
console.log(kathryn.askForRaise(), matt.askForRaise()); // 3600, 20
});
</script>
<title></title>
</head>
<body>
</body>
</html>
/my/Person.js
define(["dojo/_base/declare"], function (declare)
{
return declare(null, {
constructor: function (name, age, residence)
{
this.name = name;
this.age = age;
this.residence = residence;
}
});
});
/my/Employee.js
define(["dojo/_base/declare", "my/Person"], function (declare, Person)
{
return declare(Person, {
constructor: function (name, age, residence, salary)
{
// The "constructor" method is special: the parent class (Person)
// constructor is called automatically before this one.
this.salary = salary;
},
askForRaise: function ()
{
return this.salary * 0.02;
}
});
});
I tried to set a break point in all the call back method (return declare ...) and it never gets in there. It never gets into the require block's callback also.
Any help is appreciated

There are just a couple of small issues with your HTML file.
In your script tag that loads Dojo, you have added the data-dojo-config attribute. This is one of two ways to tell Dojo how it should behave - the other way is to define a global dojoConfig object. You've done both! So, remove the data-dojo-config attribute.
Now, Dojo needs to know about the config object just when it loads. So the dojoConfig has to be defined before the script tag that loads Dojo. Since async:true was just removed, add it to the config object instead.
Also, as Buffalo has mentioned, there's no need to include the Person and Employee modules with script tags. Dojo uses a pattern called AMD (Async Module Definitions) for loading modules. Basically that's the define and require functions you see here and there. These load the modules by very conveniently inserting the script tags for you (as long as you've told them where to find your namespace in the dojoConfig).
So the beginning of your head should be something like this:
<script>
var dojoConfig = {
parseOnLoad: true,
async: true,
packages: [{
"name": "my",
"location": location.pathname.replace(/\/[^/]+$/, "") + "/my"
}]
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js"></script>
That's actually all you need to make Dojo load your classes as it should. However, I think there's another small gotcha you may want to be aware of:
First, you require the Person module. Dojo will do its module loading magic behind the scenes and call function(Person) {...} when it's done. Next, you do the same with the Employee module and call function(Employee) {... }. You should keep in mind that you cannot guarantee that function(Person) is called before function(Employee). If, for example, you loaded Person and 100 other modules, function(Employee) would be called first.
(I mention this because I suspected that kathryn was a typo, and that you intended you use the folk object instead. I see now that that probably wasn't the case, but I'll leave it here anyway).

At least one change you'll want to make is to remove the lines
<script src="/my/Employee.js"></script>
<script src="/my/Person.js"></script>
One of the main selling points AMD modules is that you can have reusable modules without needing to add script tags everywhere in your html files.
Another debugging tip would be to check the inspector for any console errors or network errors.

Related

How to split jquery source code into multiple files when using the module pattern?

I've got some problems splitting up my jquery source code into more than one file. My real source code is a bit more complicated but the following simple example shows my problem very good. At first I would like to show you a working example with only one javascript file. Afterwards, I will describe what I tried in order to split the javascript into two files.
My html code looks like this ("./jquery" is a symbolic link to my local jquery download):
<html>
<head>
<script src="./jquery"></script>
<script src="./file1.js"></script>
</head>
<body>
<div id="content"></div>
</body>
</html>
The jquery source code in file1.js looks like this:
$(document).ready(function() {
var Test = (function() {
var content = $('#content');
var init = function() {
content.html('<p>test</p>');
};
return {
init: init
}
})();
Test.init();
});
After opening the page, "test" is displayed so that this example works as expected.
But now I want to put the whole Test part into another file file2.js. My html is basically the same but gets an additional line:
<script src="./file2.js"></script>
file1.js now contains only the call of the init function:
$(document).ready(function() {
Test.init();
});
and file2.js contains the definition of Test:
var Test = (function() {
var content = $('#content');
var init = function() {
content.html('<p>test</p>');
};
return {
init: init
}
})();
When I open the page, "test" is not displayed any more. In order to make sure that the init function is called at all, I added a console.log("test"); to the init function which is working fine. Therefore, I suppose that the function might be called before the DOM is ready, but actually I am pretty clueless. Maybe someone can give me a hint how to make that run.
Best regards and thanks in advance!
You can do several things according to your preferences...
1. Move your scripts to the end of the HTML file intead than in header...
<html>
<head>
</head>
<body>
<div id="content"></div>
</body>
<script src="./jquery"></script>
<script src="./file2.js"></script>
<script src="./file1.js"></script>
</html>
Think this problem secuencially... if you don't want to declare a var in each module referring an element in your DOM you need that the element exists first, then you can declare the "global" var to the module content. This way your original file2.js works.
Another way is to declare the content "global" to your module but init this in your init function...
var Test = (function() {
var content;
var init = function() {
content = $('#content');
content.html('<p>test</p>');
};
return {
init: init
}
})();
Now you can use the content variable in all of your module's functions.
Hope this helps, let me know.
file1 depends on file2. Make sure file1 comes ordinally after file2 in your html.
AngularJS offers dependency injection, modules, services, factories and all sorts of other goodness. Takes a bit to get used to, but well worth it IMO: much cleaner abstraction of javascript from DOM, data from presentation etc.
I appreciate your question is JQuery specific, but especially if you're starting a new site, I suggest you give Angular a try.
Modify your file2.js as follows:
var Test = {
content : $('#content'),
init : function() {
Test.content.html('<p>test</p>');
}
//, include other functions here
};
Modify your file1.js as follows:
$(document).ready(function(){
Test.init();
})
Now declare file2.js before your declare file1.js because file1.js is referencing a function from file2.js .

Build my library in JavaScript/Dojo

I will appropriate your help in creating my library in JavaScript and using Dojo.
It seems to me like a beginner problem but I can't seem to find the problem.
I am trying to create a library that is named 'edm'
The EDM.js is very simple:
define([
"dojo/_base/declare"
], function(declare) {
var EDM = declare("EDM", {
constructor: function() {
console.log("Hi EDM lib")
},
sayHi: function() {
console.log("Hi EDM lib")
}
});
edm = new EDM();
return edm;
});
The index.html to load it:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js"
data-dojo-config="async: true"></script>
<script src="../src/EDM.js" type="text/javascript"></script>
</head>
<body>
<script src="main.js" type="text/javascript"></script>
</body>
</html>
and the main.js to use the edm is:
var newObject = edm;
The idea is basically to be able to use edm as prefix for the functions in EDM.js file.
However, when loading the index.htm file I get this error: "Uncaught ReferenceError: edm is not defined"
I will appropriate any direction.
Thanks
You should use the Dojo AMD loader in stead of loading the file yourself. Remove the following <script> tag:
<script src="../src/EDM.js" type="text/javascript"></script>
Then write the following code in main.js:
require([ "../src/EDM" ], function(edm) {
var newObject = edm;
});
The advantages of doing it this way is the following:
No need to add <script> tags that slow down the page when loading
No additional objects are added to the global scope
Of course, because no objects are on global scope, you cannot retrieve the edm object directly. That's why you got that ReferenceError.
To answer your question from the comments: yes and no. Actually, you're already adding edm to the global scope in EDM.js because you didn't put var in front of the following statement:
edm = new EDM();
However, the define() callback is only executed if it's called from the Dojo AMD loader inside a require() function. So that actually means that you have to load the AMD module first and then you will be able to access edm from global scope.
So in your case, the following will work as well:
require([ "../src/EDM" ], function(bla) {
var newObject = edm;
});
As you can see in the example above, we call our module bla, however, because you added it to global scope in EDM.js, it's now available. But, in order to add it to the global scope you have to properly load the module.
But be careful, adding objects to global scope is usually not encouraged, because they can be manipulated from any code which makes it hard to debug. There are a lot of other reasons why global variables are not a good idea, you can probably find a lot more information about it on the web.

JQuery Plugin Pattern - Code Organization for multiple scripts

I'm developing a client using JQuery based on lightweighted plugin pattern as listed here.
https://github.com/jquery-boilerplate/jquery-patterns/blob/master/patterns/jquery.basic.plugin-boilerplate.js
I've been working on one file, but it's getting bloated with over 1000 lines of code. So I've decided to split scripts, but I haven't been able to locate best practice for keeping multiple scripts with jQuery.
My main script is the following:
;(function($, window, document, undefined) {
function MainClass(){
this.other = new Otherclass(); // Otherclass is defined in separate script
}
MainClass.prototype = {
...
}
$.fn.mainclass = function(){
...
}
})(jQuery, window, document);
HTML is the following:
<html>
<head>
// JQuery included
<script type="text/javascript" src="mainclass.js></script>
<script>
$(function() {
$("body").mainclass();
});
</script>
</head>
</html>
Question: I need to define otherclass on the separate file. What is the best way to accomplish this? If Plugin Pattern wasn't meant to have multiple scripts, are there any other practice suitable for this?
Thank you.
The module pattern that you are using is a good first step in the right direction. The plugin pattern was really intended to encapsulate one specific functionality for a given set of elements and follows the open/closed principle pretty well, by design (open for extension). However, it isn't a good approach for multiple object interaction due to its primary behavior as an extension method of the jQuery object.
One thing that I was able to do to split my JavaScript out into pages/multiple files was to use a combination of Namespacing and Module Augmentation/Importing/Exporting.
The namespacing was great for importing and dereferencing other portions of the application and the module pattern helped with selection of exposure and exporting just the right amount of reusable members of an object. From there, I could dereference any object that was in the namespace, create new instances from that, and so forth:
//In some common site-wide file, declare a common namespace and known base objects within it:
var App = {
View: {},
Utilities: {}
};
// view.js
App.View = (function($, window, document, undefined) {
var localProp = "Hi, i'm a private property for App.View to access";
function doSomething(){
// a private method for use
}
return {
reuseableMethod: function() {
// exported for access through App.View.reusableMethod()
}
};
})(jQuery, window, window.document, undefined);
// another script, more specific, different file
// NOTE: the import and export of App.View and view
(function($, window, document, view) {
// consume your other objects after importing them
var me = Object.create(view);
me.reuseableMethod();
function localFunction() {
//do something private
}
})(jQuery, window, window.document, App.View);

How can I split a javascript application into multiple files?

I created a javascript application with all of the code in one file. The application has grown quite a bit and I think it's time to split it up into multiple files, but I'm having a hard time figuring out how to do this. I think the problem lies with how I have decided to build the app, which uses the following template:
var myApp = function(){
//there are several global variables that all of the modules use;
var global1, global2, module1, module2;
global1 = {
prop1:1
};
//There are also several functions that are shared between modules
function globalFunction(){
}
var ModuleOne = function(){
function doSomething(){
//using the global function
globalFunction();
}
return{
doSomething:doSomething
}
};
var ModuleTwo = function(){
function doSomething(){
//module 2 also needs the global function
globalFunction();
//Use the functionality in module 1
//I can refactor this part to be loosely coupled/event driven
module1.doSomething();
}
};
module1 = new ModuleOne();
module2 = new ModuleTwo();
};
Even if all of the modules were loosely coupled and event driven, I still don't know how I would go about splitting this into multiple files given each module's reliance on the shared functions/variables. Does anyone have suggestions?
Take a look at the design pattern in this article: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth - you can split your module definition across multiple files in a way that lets common properties be shared but also lets you create variables or methods that are private just to a particular file.
The basic idea is that the individual JS files add to the same module with code like this:
var MODULE = (function (my) {
var privateToThisFile = "something";
// add capabilities...
my.publicProperty = "something";
return my;
}(MODULE || {}));
Where in each JS file if MODULE is already defined (from another JS file) you add to it otherwise you create it. You can set it up so that it (mostly) doesn't matter what order the various files are included in.
The article details several variations, and of course you'll probably come up with your own tweaks...
not to add to the confusion, but coming from a C++ background, I've tried to construct something that resembles something like a c++ namespace in the manner described below. it works, but I'd like to know if this is an acceptable pattern for the OP ?
--------------------------------file main.js:----------------
var namespacename = function(){}
namespacename.mainvalue = 5;
namespacename.maintest = function() {
var cm = new namespacename.game();
cm.callme();
}
--------------------------------file game.js:----------------
namespacename.gamevalue = 15;
namespacename.game = function(){
this.callme = function(){
console.log( "callme" );
}
}
namespacename.gametest = function() {
console.log( "gametest:gamevalue:" + this.gamevalue );
console.log( "gametest:mainvalue:" + this.mainvalue );
}
--------------------------------file index.html:--------------
<html>
<head>
<title>testbed</title>
</head>
<body onload="init();">
</body>
<script type="text/javascript" src="main.js"></script>
<script type="text/javascript" src="game.js"></script>
<script type="text/javascript">
init = function()
{
namespacename.maintest();
namespacename.gametest();
console.log( "html main:" + namespacename.mainvalue );
console.log( "html game:" + namespacename.gamevalue );
}
</script>
</html>
Give require.js a shot. http://requirejs.org/
Example:
require(["dir/file"], function() {
// Called when file.js loads
});
You can put the shared functions and shared modules on the myApp object so they don't pollute the global namespace, but can be accessed anywhere without being inside the same closure.
myApp.moduleOne = function() {...}
myApp.moduleTwo = function() {...}
myApp.globalFunction = function() {...}
Then, you can define them in any file and use them in any file.
You could also just break the file up into multiple files, but require them to be included in a specific order that preserves your closure. If you're breaking up the files for practical editing reasons, but recombining and minimizing them for actual deployment, then this wouldn't cost you anything in terms of how you write code or how it's deployed, but would give you lots of smaller files for editing convenience.
My favorite solution to this is use server side scripting to include the other files inside my "main" file. For example, using Perl's Template Toolkit:
var myApp = function(){
[% INCLUDE lib/module1.js %]
[% INCLUDE lib/module2.js %]
[% INCLUDE lib/module3.js %]
}
Or PHP:
var myApp = function(){
<?php
include 'lib/module1.js';
include 'lib/module2.js';
?>
}

How do I pass argument to anonymous Javascript function?

I am writing a simple counter, and I would like to make installation of this counter very simple for users. One of the simplest counter code (for users who install it) I ever see was Google Analytics Code
So I would like to store main code in a file and user who will install my counter will need just to set websiteID like this:
<html><head><title></title></head><body>
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var websiteId = 'XXXXX';
</script>
</body></html>
Here is my code:
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var page = _gat.init('new');
</script>
and this is my JS file:
(function() {
var z = '_gat';
var aa = function init(data) { alert(data); alert(z);};
function na() {
return new z.aa();
}
na();
})();
I tried to understand Google Analytics javascript code but I failed to do this. Can anyone suggest how can I specify variable between tags and then read it in anonymous function which is located in a javascript file ?
Thanks.
In your example, websiteId is a global variable. So it is accessible everywhere including anonymous functions unless there is a local variable with the same name
<script> var websiteId = "something"; </script>
Later in the page or included js file...
(function() {
alert(websiteId); //this should work
})();
Can anyone suggest how can I specify variable between tags and then read it [...]
Not if your tag has both a SRC attribute and JS content.
<script type="text/javascript" src="http:/x.com/x.js"></script>
.. is different from,
<script type="text/javascript">
var x = 1;
</script>
One framework that optionally adds JS variables to SCRIPT tags is Dojo. So if you're using Dojo you can add variables to the global djConfig hash by writing,
<script type="text/javascript" src="mxclientsystem/dojo/dojo.js"
djConfig="
usePlainJson: true,
parseOnLoad: true
">
</script>
Dojo does this by running through the SCRIPT tags and evaluating the custom djConfig attribute.
This does not, however solve your problem.
You do really want two SCRIPT tags. One saying,
<script type="text/javascript">
var websiteId = '123456';
</script>
which will set a global variable websiteId and a second one,
<script type="text/javascript" src="http:/x.com/myreporter.js"></script>
which can load from anywhere and read out the websiteId variable and, I assume, report it back.
You can pass variables to an anonymous function like so:
(function(arg1, arg2, arg3) {
alert(arg1);
alert(arg2);
alert(arg3);
})("let's", "go", "redsox");
// will alert "let's", then "go", then "redsox" :)
I'm not entirely clear about what you're asking, but...
You can tag any HTML element with an id attribute, then use
document.getEntityById() to retrieve that specific element.
You can also give any HTML element user-defined attributes having names of your own choosing, then get and set them for that element within Javascript.
I think you've got a bit confused with how JS objects are called.
z is a String, '_gat'. You can't call aa() on it because a String has no member called aa. aa is a standalone function stored in a local variable. Even if you did call aa(), it doesn't return anything, so using the new operator on its results is meaningless. new can only be called on constructor-functions.
I guess you mean something like:
var _gat= function() {
// Private variable
//
var data= null;
// Object to put in window._gat
//
return {
// Set the private variable
//
init: function(d) {
data= d;
}
};
}();
Then calling _gat.init('foo') as in your second example would set the variable to website ID 'foo'. This works because the _gat object is the return {init: function() {...}} object defined inside the anonymous function, keeping a reference (a ‘closure’) on the hidden data variable.
If you specify a src attribute as part of a script element, any code within the script element tags themselves will not be executed. However, you can add this functionality with the following code. I got this technique from Crockford (I believe it was him), where he uses it in of his talks on the unrelated topic of rendering performance and asynchronously loading scripts into a page to that end.
JavaScript:
(function() {
// Using inner class example from bobince's answer
var _gat = (function() {
var data= null;
return {
init: function(d) {
console.info("Configuration data: ", d);
data = d;
}
}
})();
// Method 1: Extract configuration by ID (SEE FOOT NOTE)
var config = document.getElementById("my-counter-apps-unique-and-long-to-avoid-collision-id").innerHTML;
// Method 2: search all script tags for the script with the expected name
var scripts = document.getElementsByTagName("script");
for ( var i=0, l=scripts.length; i<l; ++i ) {
if ( scripts[i].src = "some-script.js" ) {
config = scripts[i].innerHTML;
break;
}
}
_gat.init( eval("(" +config+ ")") );
})();
HTML:
<script type="text/javascript" src="some-script.js" id="my-counter-apps-unique-and-long-to-avoid-collision-id">
{some: "foo", config: "bar", settings: 123}
</script>
Both methods have their draw backs:
Using a unique and non-colliding ID will make determining the proper script element more precise and faster; however, this is not valid HTML4/XHTML markup. In HTML5, you can define arbitrary attributes, so it wont be an issue at that time
This method is valid HTML markup; however, the simple comparison that I have shown can be easily broken if your url is subject to change (e.g.: http vs https) and a more robust comparison method may be in order
A note on eval
Both methods make use of eval. The typical mantra concerning this feature is that "eval is evil." However, that goes with say that using eval without knowing the dangers of eval is evil.
In this case, AFAIK, the data contained within the script tags is not subject to inject attack since the eval'ing script (the code shown) is executed as soon as that element is reached when parsing the HTML into the DOM. Scripts that may have been defined previously are unable to access the data contained within the counter's script tags as that node does not exist in the DOM tree at the point when they are executed.
It may be the case that a well timed setTimeout executed from a previously included script may be able to run at the time between the counter's script's inclusion and the time of the eval; however, this may or may not be the case, and if possible, may not be so consistently depending on CPU load, etc.
Moral of the story, if you're worried about it, include a non-eval'ing JSON parser and use that instead.

Categories