I am toying around with a pretty intensive ajax based jquery web application. It is getting to a point where I almost loose track of what events that should trigger what actions etc.
I am sort of left with a feeling that my javascript structure is wrong, on a more basic level. How do you guys structure your javascript/jquery code, the event handling etc., any advise for a newbie javascript developer.
AMDS!
It's been awhile since first answers got posted to this question and many things have changed.
First and foremost, the JS browser world seems to be moving towards AMDs (asynchronous module definition) for code organization.
The way that works is you write ALL your code as AMD modules, e.g.:
define('moduleName', ['dependency1', 'dependency2'], function (dependency1, dependency2) {
/*This function will get triggered only after all dependency modules loaded*/
var module = {/*whatever module object, can be any JS variable here really*/};
return module;
});
And then modules get loaded using AMD loaders like curl.js or require.js etc, for example:
curl(
[
'myApp/moduleA',
'myApp/moduleB'
],
).then(
function success (A, B) {
// load myApp here!
},
function failure (ex) {
alert('myApp didn't load. reason: ' + ex.message);
}
);
Advantages are:
You only have to include single <script> element on your page that loads AMD loader itself (some of them are quite tiny).
After that all JS files will be fetched automatically in asynchronous NON BLOCKING! fashion, thus way faster!
Necessary modules will get executed only after its dependencies got loaded.
Modular (which means code that is easier to maintain and re-use).
Global variables pollution can be completely curbed if used correctly.
Honestly, once concept has clicked in your head, you'll never go back to your old ways.
P.S: jQuery does register itself as AMD module starting from version 1.7.
More information on AMDS:
https://github.com/cujojs/curl
http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition
http://requirejs.org/
http://www.bennadel.com/blog/2275-Using-RequireJS-For-Asynchronous-Script-Loading-And-JavaScript-Dependency-Management.htm
https://github.com/Integralist/Blog-Posts/blob/master/2012-01-04-Beginners-guide-to-AMD-and-RequireJS.md
For javascript code I found the following links from Christian Heilmann indispensable
The module pattern
Configuring scripts
I also really like the method described by Peter Michaux here
For jQuery, I heartily recommend reading the guides on Authoring and I found this tutorial on jQuery plugin patterns very good
To keep my events in control I use a publish/subscribe mechanism
jQuery.subscribe = function( eventName, obj, method ){
$(window).bind( eventName, function() {
obj[method].apply( obj, Array.prototype.slice.call( arguments, 1 ) );
});
return jQuery;
}
jQuery.publish = function(eventName){
$( window ).trigger( eventName, Array.prototype.slice.call( arguments, 1 ) );
return jQuery;
}
Here's an example of its use
// a couple of objects to work with
var myObj = {
method1: function( arg ) {
alert( 'myObj::method1 says: '+arg );
},
method2: function( arg1, arg2 ) {
alert( arg1 );
//republish
$.publish( 'anEventNameIMadeUp', arg2 );
}
}
var myOtherObj = {
say: function(arg){
alert('myOtherObj::say says: ' + arg);
}
}
// you can then have all your event connections in one place
//myObj::method2 is now listening for the 'start' event
$.subscribe( 'start', myObj, 'method2' );
//myOtherObj::say is now listening for the 'another' event
$.subscribe( 'anotherEvent', myOtherObj, 'say' );
//myObj::method1 is now listening for the 'anEventNameIMadeUp' event
$.subscribe( 'anEventNameIMadeUp', myObj, 'method1' );
//so is myOtherObj::say
$.subscribe( 'anEventNameIMadeUp', myOtherObj, 'say' );
// ok, trigger some events (this could happen anywhere)
$.publish( 'start', 'message1', 'message2' );
$.publish( 'anotherEvent', 'another message' );
I definitely recommend reading up on the object literal pattern in addition to the module pattern; here's a good writeup:
http://ajaxian.com/archives/show-love-to-the-object-literal
(function($, window, slice)
{
$.subscribe = function(eventName, obj, method)
{
$(window).bind(eventName, function()
{
obj[method].apply(obj, slice.call(arguments, 1));
});
return $;
};
$.publish = function(eventName)
{
$(window).trigger(eventName, slice.call(arguments, 1));
return jQuery;
};
})(jQuery, window, Array.prototype.slice);
To add to the existing answers, here's a great post that covers more advanced techniques that build on the Module Pattern.
Once your Javascript code reaches a certain size, you'll inevitably want to refactor it by breaking it into multiple files / modules / sub-modules. If you're not sure how to accomplish this using the module pattern, this article is a must-read.
My js files usually follow a naming convention similar to this :
xxx.utility.js
mypage.events.js
xxx.common.js
/lib/
/OS-DoNotDistribute/lib/
Where
'mypage' is the name of the html,
aspx, php, etc file.
'xxx' is the concept. (i.e. orders.common.js)
'utility' signifies it's a reusable
library script (i.e. ajax.utility.js, controlfader.utility.js)
'common' is reusable functionality
for this app, but not reusable across
other projects
'lib' is a subdirectory for any external or library scripts
'OS-DoNotDistribute' is a subdirectory to ensure no OS licensed code is distributed if the app is ever sold.
Also, for ajax, I have a special naming convention for call back functions, so it's easy to tell what they are.
I'm not sure it that's close to what you were looking for, but I hope it helps.
I really like these articles:
http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html
http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/
They helped me to understand how telerik creates extensions for asp.net mvc.
I like the idea of AMDs (see nix's answer).
But I typically compile all my JS files into one JS file.
In that case the asynchronous part is not needed. So I wrote a little "Infile Module Loader".
Here it is: https://codereview.stackexchange.com/questions/14530/a-little-infile-amd
We can use mvc pattern in our javascript-jquery applications.
(Backbone.js, knockout.js vs.... ) are mature libraries we can use for this aim.
Related
I'm not sure I'm even asking the right question here, sorry, but I think the two general ones are:
In what way do you need to modify a node.js package using require etc to be used as a plain embedded script/library in HTML?
How do you call a class constructor (?) in JS as a function to validate a form field?
I'm trying to use this small JS library NoSwearingPlease (which is an npm package) in an environment with no node or build system – so I'm just trying to call it like you would jQuery or something with a script & src in the HTML, and then utilise it with a small inline script.
I can see a couple of things are required to get this working:
the JSON file needs to be called in a different way (not using require etc)
the checker variable needs to be rewritten, again without require
I attempted using jQuery getJSON but I just don't understand the class & scope bits of the library enough to use it I think:
var noswearlist = $.getJSON( "./noswearing-swears.json" );
function() {
console.log( "got swear list from inline script" );
})
.fail(function() {
console.log( "failed to get swear list" );
})
noswearlist.done(function() {
console.log( "done callback as child of noswearlist variable" );
var checker = new NoSwearing(noswearlist);
console.log(checker);
});
Please halp. Thanks!
No need to modify, when outside of node the class is just appended to window (global):
fetch("https://cdn.jsdelivr.net/gh/ThreeLetters/NoSwearingPlease#master/swears.json").then(response => {
return response.json();
}).then(data => {
var noSwearing = new NoSwearing(data);
console.log(noSwearing.check("squarehead"));
});
<script src="https://cdn.jsdelivr.net/gh/ThreeLetters/NoSwearingPlease#master/index.js"></script>
In the future, you can answer this type of question on your own by looking through the source code and looking up things you don't understand. That being said, here's what I was able to gather doing that myself.
For your first question, if you have no build tools you can't use require, you have to hope your NPM package supports adding the class to the window or has a UMD export (which in this case, it does). If so, you can download the source code or use a CDN like JSDelivr and add a <script> tag to link it.
<script src="https://cdn.jsdelivr.net/gh/ThreeLetters/NoSwearingPlease#master/index.js"></script>
I'm having a hard time deciphering your script (it has a few syntax errors as far as I can tell), so here's what you do if you have a variable ns containing the JSON and the string str that you need to check:
var checker = new NoSwearing(ns);
checker.check(str);
As an aside, you should really use build tools to optimize your bundle size and make using packages a lot easier. And consider dropping jQuery for document.querySelector, fetch/XMLHttpRequest, and other modern JavaScript APIs.
I am looking #Domenic's simple example of using requirejs, from this answer:
simple example for using require.js
which I am including here.
shirt.js:
define({
color: "black",
size : "large"
});
logger.js:
define(function (require) {
var shirt = require("./shirt");
return {
logTheShirt: function () {
console.log("color: " + shirt.color + ", size: " + shirt.size);
}
};
});
main.js:
define(function (require) {
var shirt = require("./shirt");
var logger = require("./logger");
alert("Shirt color is: " + shirt.color);
logger.logTheShirt();
});
main.html:
<script data-main="../js/main" src="../js/require.js"></script>
There's something very strange going on:
at the point where shirt.color is used in main.js,
shirt.js and logger.js have just been scheduled to be loaded, asynchonously (I presume),
so shirt.js hasn't actually been read yet. The reason I presume the loading is asynchronous is that my impression is that synchronous loading has been pretty much outlawed in javascript in chrome (XMLHttpRequest still has an option to be synchronous, but if used, it warns on the chrome console Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.).
And yet, this little app seems to work, reliably.
It even works reliably if I replace "./shirt.js" by a url referring to a resource on the other
side of the world, and I clear my browser cache before loading the html page.
How can this be??
If I look at timings in chrome dev console, it appears that the time-consuming shirt.js load
actually happened before the function that requested it even started.
I.e. somehow it knew to load shirt.js before anything in the program referred to "./shirt" at all.
It seems there is some very sneaky magic going on here.
So I'm interested to know:
how did requirejs know to load shirt.js before anything asked for it?
to what extent can this be relied on?
how would one modify this example to avoid relying on the sneaky magic?
for those of us who don't trust sneaky magic, is there a way to disable it when using requirejs?
how did requirejs know to load shirt.js before anything asked for it?
This is your module:
define(function (require) {
var shirt = require("./shirt");
var logger = require("./logger");
alert("Shirt color is: " + shirt.color);
logger.logTheShirt();
});
When define is called, RequireJS detects that it was called without a dependency list. So it scans the callback you pass for instances of the require call taking a single argument which is a string literal, and it grabs the single argument and makes a list of these arguments that it takes as the dependency list of the module. Your module becomes functionally equivalent to this:
define(["require", "./shirt", "./logger"], function (require) {
var shirt = require("./shirt");
var logger = require("./logger");
alert("Shirt color is: " + shirt.color);
logger.logTheShirt();
});
So ./shirt and ./logger are loaded before the callback is actually called. Then when require("./shirt") and require("./logger") are executed, they are just lookups in a map of already loaded modules. (And, because of this, calls to require with a single string argument can only work when called in a callback passed to define. Otherwise, you get the dreaded "Module has not been loaded yet for context" error.)
This capability is called the "CommonJS sugar" because a require call that uses a single parameter which is a string and returns a module is what CommonJS supports natively. The native AMD require call takes an array of dependencies as the first argument and an optional callback to which the resolved modules are passed.
to what extent can this be relied on?
I've relied on the CommonJS sugar for hundred of modules without problem.
The one limitation to this pattern is if you try to pass something else than a string literal to require. For instance if you do this:
define(function (require) {
var shirtName = "./shirt";
var shirt = require(shirtName);
This will throw off RequireJS. It won't detect that your module needs the ./shirt module and you'll get the error I mentioned above.
how would one modify this example to avoid relying on the sneaky magic?
define(["./shirt", "./logger"], function (shirt, logger) {
alert("Shirt color is: " + shirt.color);
logger.logTheShirt();
});
for those of us who don't trust sneaky magic, is there a way to disable it when using requirejs?
There's no flag you can use to prevent RequireJS from supporting the CommonJS sugar. If you want to avoid relying on it in your own code, you can code your modules like I've shown in the previous snippet: call define with a list of dependencies as the first argument, and get the modules as arguments of your callback.
This being said, I see no good reason to do that. I've used RequireJS for years and if anything I've been moving code that uses define with a list of dependencies to code that relies on the CommonJS sugar. I find that the latter works better with various development tools.
I have been studying framework development for a few weeks, and I ran across what is highly suggested and pressured in the world of lib development, Immediately-invoking Anonymous Functions.
I never can get it to work, and I have failed to find a resource that explains in-detail the use and logic behind it.
Here's what I know so far:
It's immediately invoking - It runs everything anonymously, immediately.
It's anonymous - It does not carry a name therefore the code inside of it is not "reachable" by exterior code.
You can pass global window, object and undefined parameters - That's about all I know on that, but do not understand them completely.
I am looking not only for a detailed resource, but one that explains the logic behind it. Because I find it very illogical.
Here's what I have:
(function( window, document, undefined ) {
window.myThingy = myThingy;
var myThingy = function() {
};
myThingy.prototype = {
constructor: myThingy,
create: function( elementToBeCreated ) {
return document.createElement( elementToBeCreated );
}
};
})( window, document );
Then,
myThingy().create("div");
But it is still saying myThingy() [object] is not a function.
What am I doing wrong? Why should I use immediately-invoking functions and not just create a global myThingy = function() object? Why do I have to use window?
I know there are several resources on the net about this, but I can't understand any of it. Some of them go half-way into detail, some of them try to go into detail, but fail to explain the critical stuff. Why is this so stressed when developing a framework?
Don't worry, I'm not trying to "re-invent the wheel", but I am trying, however, to actually learn JavaScript, not just the pre-packaged stuff.
A good answer should contain:
A good resource where it explains the logic behind immediately invoking anonymous functions
An insight to that link
What I am doing wrong with the code I provided
First off, you have not yet defined your function when you try to assign it to the global object so it is undefined:
window.myThingy = myThingy;
console.log(myThingy);//undefined
You need to do the assignment after myThingy is defined:
(function( window, document, undefined ) {
var myThingy = function() {
};
myThingy.prototype = {
constructor: myThingy,
create: function( elementToBeCreated ) {
return document.createElement( elementToBeCreated );
}
};
window.myThingy = myThingy;
})( window, document );
Okay, next, you cannot use
myThingy.create("div");
because myThingy is a function and not an object. Function objects are created when the new keyword is issued to a function. You can make this change to convert your function into a function object:
window.myThingy = new myThingy();//create a function object
This pattern is not how all frameworks are implemented, but similar. Sometimes there is more abstraction. However, making these changes will allow your approach to work.
Here is a demo of your code: http://jsfiddle.net/ZjRJW/
Links
Here are some of my favorites:
http://ejohn.org/blog/simple-class-instantiation/
http://ejohn.org/apps/learn/
http://ejohn.org/blog/simple-javascript-inheritance/
http://jibbering.com/faq/notes/closures/
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model
http://javascript.crockford.com/prototypal.html
If you want to learn about JS design patterns, I highly recommend Addy Osmani's books/articles. He keeps things very simple and usually supplies quite a bit of example code to help you understand. As far as your code and implementing a design pattern is concerned, it depends on what you want your code to do, and how you want your code/objects to behave. Understanding your requirements/goals are very important before you start coding so you don't get lost in a spaghetti of patterns that really aren't solving a specific problem.
In some cases, implementing a pattern intended for a complex, large application is simply overkill.
Since someone else already correctly pointed out the issues with your code, I'll just leave it there.
I've created a jQuery UI widget which is dependent on some other custom JavaScript modules. I fetch these modules using requirejs during the "_create" method of the widget. This actually works great if, I have my end consumers define my "data-main" property. However, in the situation where my consumers are using requirejs on their own, and defining their own "data-main" property, this doesn't work.
Since I'm using requirejs to inject scripts via my widget from a totally different server, I run into a few problems with requirejs's normal way of dealing with this.
First, I can't use a package.json file unless I assume that all of my consumers have a package.json which contains the exact same resources as I have. On top of that, I've got DEV, TEST and PROD server URLs to deal with.
Second I can't use require.config to set my baseUrl during a load on their server, cause it may break everything that they are using require for.
The current implementation I have working requires the consumer to add a script reference to require with my data-main location (external server). Then add a script ref to my widget (external server). This works because nobody else at my company has ever even heard of requirejs :). The second I start showing them how to bundle all of their code into reusable JavaScript modules my solution is broken.
I want to come up with a solution whereas the end consumer can simply reference my single JavaScript widget, which in turn loads everything it needs to function.
Any suggestions on how to do this? I've thought about hacking my own version of require with a static data-main, then just assume they can have multiple requirejs libs. I WOULD HATE TO DO THAT...but I can't really think of a better way.
Here is what I am going to do...
Couple of notes:
I'm using the jQuery UI widget factory pattern (but this isn't exactly a widget)
The widget code lives on a remote server and consumers only reference it, don't download it
I'm using requirejs to load widget dependencies
I want the greatest ease-of-use for the consuming developer
Since it's required that my jQuery UI widget be loaded ASAP so that the consumer has the context of the widget right away ( $(selector).mywidget ) I've decided to tackle my problem inside of the _create method.
This code basically installs requirejs if it doesn't exist, then uses it to install an array of requirements which the aforementioned widget needs to consume. This allows me to assume that the end user can reference my "widget" script by URL, tack on a "data-requiremodule" attribute of the same name, and get a complete list of remote dependencies.
_create: function () {
var widget = this;
widget._establish(widget, function () {
widget._install(widget);
});
},
_getBaseURL: function (scriptId, callback) {
var str = $('script[data-requiremodule="' + scriptId + '"]').attr('src');
if (callback) callback(str.substring(str.search(/scripts/i), 0));
},
_require: function (requirementAry, baseUrl, callback) {
require.config({ baseUrl: baseUrl });
require(requirementAry, function () {
if (callback) callback();
});
},
_establish: function (widget, callback) {
if (typeof require === 'undefined') {
widget._getBaseURL(widget._configurations.widgetName, function (baseUrl) {
var requireUrl = baseUrl + 'scripts/require.min.js';
baseUrl = baseUrl + 'scripts/';
$.getScript(requireUrl, function (data, textStatus) {
widget._require(widget._configurations.requiredLibs, baseUrl, function () {
callback(textStatus);
});
});
});
}
},
I'm not showing my "_configurations" object here...but you get the idea. I hope this helps someone else besides me :).
Iam trying to get better in javascript coding. Away from 1000 lines of code in one file. But iam not sure if this is the "right" way:
RequireJS to load files when needed inside "boot.js":
require([
"library/jquery.form/jquery.form",
"app/eventManager",
"app/myapp"
], function() {
$(function() {
MyApp.init();
});
});
MyApp.js
var MyApp = {
init: function() {
MyApp.mainController();
},
// this is our controller, only load stuff needed..
mainController: function() {
//controller = set from php/zendframework
switch (controller) {
case 'admin':
MyApp.initAdmin();
break;
default:
break;
}
},
// action for admin controller
initAdmin: function() {
//lazy load
require(["app/admin/admin"], function(){
MyApp.admin.init();
});
}};
MyApp.admin.js
MyApp.admin = {
init : function() {
if (permisson != 'admin') {
console.log('Permission denied.');
return false;
}
MyApp.admin.dashboard.init();
}
};
MyApp.admin.dashboard = {
init: function() {
MyApp.admin.dashboard.connectEventHandlers();
MyApp.admin.dashboard.connectEvents();
MyApp.admin.dashboard.getUserList('#admin-user-list');
},
connectEvents: function () {
EventManager.subscribe("doClearCache", function() {
MyApp.admin.dashboard.doClearCache(url);
});
EventManager.subscribe("doDeleteUser", function() {
MyApp.admin.dashboard.doDeleteUser(url);
});
},
What other "styles" are common? or this a goodway to structure code? THere a lot of examples in the net, but i was not able to find "real life" code..
And one of biggest "problems" when does i need ".prototype" ?
JavaScript Patterns is a good reference for various ways of structuring code.
It would also be a good idea to study the source code of libraries such as jQuery.
One change I would make to your code is to avoid repeating 'event' strings everywhere.
You could reduce this by doing something like:
var app = {
events : {
someEvent : "someEvent"
}
}
EventManager.subscribe(app.events.someEvent, someFn);
EventManager.publish(app.events.someEvent);
I would also avoid calling console.log directly and use a wrapper such as this which provides a fallback if not console is available
N.B Angus Croll has a decent blog where he mentions js structure/namespacing etc
and there is some really good knowledge being shared over at JsMentors from well versed js ninjas
I defer to Douglass Crockford on all matters pertaining to JavaScript best practices.
Here is his homepage: http://javascript.crockford.com/.
Here is a great book on what to do and what not to do in JavaScript. http://www.amazon.com/exec/obidos/ASIN/0596517742/wrrrldwideweb
Here is his amazing tool which can automatically tell you if you are employing any worst practices. http://www.jslint.com/
As to the prototype question, you use prototype when you want to employ prototypal inheritance, or create a "static" class function which will be present for all instances of that class without consuming memory for each instance.
Require.js is great tool, you can use it also on the client side. But be careful when you use it on mobile. In such case you should either use the editor to navigate better in one file or use thing like sprocket. It is a "precompiler", does not put any additional library to your code.
I passed through your sliced up code. Probably you should define the different parts as modules, read the requirejs documentation for defining modules, it gives good assistance.
But think twice whether you really need for organizing your code an extra library.
In case you are building something more complex, for example with multiple product modules and sub modules, I recommend creating a context hierachy for your modules. Also make the UI components to be self-contained so that you have templates, css, logic, assets, localization etc for a particular UI component in a single place.
If you need to refer a reference architecture for large scale js development see http://boilerplatejs.org. I'm the main author of it and it demonstrates a lot of patterns that are useful in complex product development.