Azavea Labs

Where software engineering meets GIS.

Sometimes you feel like using modules

I’m going to go out on a limb here, and admit I enjoy Javascript.

*deep sigh* Okay, now that that’s out of the way, lets talk about writing good code.

As javascript apps mature, the need for organization and modularity becomes more important. The days of simply inlining your code in the HTML, or keeping all your code in one giant file, or rolling your own class system are fading. If you’re experienced with Javascript, you’ve probably written your own class system at some point, or code loading solution, or had to stitch together plugins for one framework all while your code is written in another. These are all simple solutions to a complex problem, and as is a common theme in software, you probably missed some edge cases. Inlining your code is hard to maintain, and isn’t modular, developing with a team in a single giant file is a nightmare, and rolling your own class loader means lack of compatibility and dealing with cross browser issues. The truth is until recently your new jQuery plugin was written differently than your nice custom layer for Openlayers, was different from your custom Dojo widget, was… well you get the point. You couldn’t expect to write them in the same way, or expect them to arrive at the browser in the same file at the same time. (If you’ve used Dojo, Ext, OpenLayers, jQuery, or Node.JS then I hope you know what I mean)

So, what’s a Javascript developer to do? The language is flexible and forgiving, and there hasn’t been something to standardize your code around, until recently. You might have noticed that the internet is pretty good at coming up with standards for sharing information and software. That’s why I was excited to see the proposal and development of the AMD API. AMD in this case stands for Asynchronous Module Definition. Basically it’s a consistent way to package your code, and it makes it significantly easier to reuse later down the road. A number of major Javascript frameworks have already embraced AMD, including jQuery, Node.JS, Dojo, and others, and I’d like to give you a preview here to hopefully inspire developers to give it a try. More importantly modules, and module loaders are proposed to be part of the spec for the next version of Javascript named “Harmony“, see Modules, and Module Loaders.

So, you like jQuery, modules, and you’re ready to open up an example and tinker around? RequireJS has you covered with a great walkthrough here: http://requirejs.org/docs/download.html#samplejquery . I’d enjoy walking through it on this blog, but it might be beyond the scope of this article. Let me know in the comments if you’d like to see more about this.

So, I wanted to provide a more complicated example, which I hope will be helpful to those looking to make nicely namespaced, properly constructable objects in Javascript. Lets pretend we had the following spec:

1.) Our class should use a private static dictionary of globally unique names that have been booped.
2.) These should be kept long-term, in localStorage when possible
3.) Our class should accept verbs other than boop, and should be extendable

So, lets get fancy for a second, and design something that is re-usable and modular. I’m picturing… A storage class, a smart globally static list class, and our main verb class that is configurable. Lets get to it:

Lets define a basic reusable storage module, something like:

define('storage', [ ], function( ) {
    //private static in-memory storage
    var _data = {};

    var that = {
        hasLocalStorage: function() { ... }
        set: function(key, value) { ... },
        get: function(key) { ... }
    };

    var ClassConstructor = function(name) {
        if (!name || name == "") { throw "Name not provided"; }
        this.prefix = name;
    };
    $.extend(ClassConstructor.prototype, that);
    return ClassConstructor;
});

Full Source for storage.js

and… lets define a class that uses that storage to maintain a globally unique list:

define('unique', ['storage'], function(Storage) {
    //private _globally static_ storage object -- will be shared with other instances of "Unique"
    //you probably wouldn't want this for this implementation, but hey, it's an example, so I wanted
    //to show how to do it.
    var _storage = null;

    var that = {
        setIfUnique: function(key) { ... }
    };

    var ClassConstructor = function(name) {
        if (!name || name == "") { throw "Name not provided"; }
        _storage = new Storage(name);
    };
    $.extend(ClassConstructor.prototype, that);
    return ClassConstructor;
});

Full Source for unique.js

and… lets define a class that uses the unique list, and takes a verb to ‘boop.’

define('booper', ['unique'], function(Unique) {
    var that = {
        //private storage, but not static, local to this object
        _unique: null,
        _verb: 'unset',

        verbObject: function(name) { ...  }
    };

    var ClassConstructor = function(verb) {
        this._verb =  verb || "boop";
        this._unique = new Unique(this._verb);
        this[this._verb] = this.verbObject;
    };
    $.extend(ClassConstructor.prototype, that);
    return ClassConstructor;
});

Full Source for booper.js

so, now we just need a basic web page to test this with:

<html>
    <head>
        <script data-main="js/index-main.js" src="js/require-jquery.js"></script>
    </head>
    <body>
        <h3>Boop em!</h3>
        <input type="text" id="name" name="name"
            style="width:300px"
            placeholder="Enter name to boop, limit once per name"
        />
    </body>
</html>

and how about some basic page code:

require(["jquery", "booper"], function($, Booper) {

    //prep
    var b = new Booper();

    //events
    var doBoop = function(evt) {
        b.boop( $("#name").val() );
    };

    $("#name").on('change', doBoop);
    $("#btnBoop").on('click', doBoop);
});

Full Source for index-main.js

Putting it all together with a working example:
Working Example!

Obviously, this example didn’t need to be this complicated, but we gained a lot from a little bit of extra work. We’ve built three easy modules, that can be easily maintained, extended, and reused. We have a hugely open and flexible page, and when we’re ready for production, we can compact and minify all those files into a single optimized build.

So, you’ll notice I added a somewhat generic three line chunk at the end of each class module. This is just some basic constructor logic so you get the nice internal reference to ‘this’, and you can initialize new objects with “new Foo()”, instead of only having one copy, etc, etc.

I hope you enjoyed this example, and if you’re interested in Azavea’s other projects, checkout our GitHub!