selfcontained[web development]

Articles tagged with "javascript" (34)

flipflop 0.1.0 - configurable urls

Saturday September 14, 2013
By Brad Harris

I released a new version of flipflop that has support for configurable urls. Details are in the readme file, but in short, when you generate a new flipflop blog, part of the config in the blog.json file will now include a section for routes. If you have an existing flipflop blog and want to update to the latest, you can add this section to your blog.json config file. You may also want/need to update a few of your templates, depending on how much you've changed them. Check this commit to see an example of what changes to make.

"routes": {
    "archive": "/archive",
    "article": "/:year/:month/:day/:slug",
    "error": "/404.html",
    "homepage": "/",
    "feed": "/feed/rss.xml",
    "tag": "/tag/:tag"
}

This will allow for customizing the url, such as adding a prefix to your blog:

"routes": {
    "archive": "/blog/archive",
    "article": "/blog/:year/:month/:day/:slug",
    "error": "/blog/404.html",
    "homepage": "/blog",
    "feed": "/blog/feed/rss.xml",
    "tag": "/blog/tag/:tag"
}

There are a few special things to note with routes:

  • The article route requires a :slug param. Available params are:
    • :year
    • :month
    • :day
    • :slug (required)
  • The tag route requires a :tag param. Available params are:
    • :tag (required)

using express with broadway

Thursday September 20, 2012
By Brad Harris

Express is by no doubt an extremely popular http application server/framework for node.js. In this article I'd like to demonstrate how you can take advantage of broadway and express together.

In this approach, we'll treat the http server that express provides as just another plugin to our broadway application.

express http plugin

First we'll create an http plugin encapsulating express.

// http.js

var express = require('express');

var HttpPlugin = exports;

HttpPlugin.name = 'http';

HttpPlugin.attach = function(options) {
    var app = this;

    var server = app.http = express();
    server.use(server.router);

    require('./routes')(app);
};

HttpPlugin.init = function(done) {
    done();
};

I'd also suggest defining your routes in their own module(s), and passing along the broadway application. This will allow them to take full advantage of any other functionality your application acquires through other plugins.

// routes.js
module.exports = function(app) {

    app.http.get('/', function(req, res){
        res.send('express on broadway');
    });

};

broadway.concat(express)

Next we'll create a broadway application and toss in our http plugin.

// app.js

var broadway = require('broadway'),
    app = new broadway.App();

app.use(require('./http'));

app.init(function(err) {
    app.http.listen(8080);
});

You can also just module.exports = app.http if you're using something like up and need to export an http server from your main applicaiton.

krakens.release()

Finally, fire up your application

>node app.js

That's all there is to it. In this example, the http server is just one piece of our application, and we can bolt on additional functionality as needed through more plugins.

decoupling your node.js application with broadway

Tuesday September 18, 2012
By Brad Harris

the why

Why should you worry about decoupling your node.js application? Can't you just use the module pattern and require() away? Sure, sort of...until your application starts to grow, and module's begin to have cross dependencies. In reality, you can avoid cross dependencies between modules for most small to medium sized applications, but as your application grows, you may run into cyclic dependencies, which can be hard to decipher and debug. Without going into detail on what those are (follow those links if you're wondering), I present, a contrived example.

var ModuleA = require('module-a'),
    ModuleB = require('module-b');

var ModuleC = module.exports = function() {
    this.myB = new ModuleB();
};

ModuleC.prototype = {

    /** amazin' function! */
    amazinFunction : function() {
        if(ModuleA.isAmazin(this.myB) {
            this.beginAwesomness();
        }else {
            this.sadPanda();
        }
    },

    beginAwesomness : function() { /** awesome stuff */ },

    sadPanda : function() { /** sad stuff */ }

};

Here ModuleC is exported, and is a pretty basic function/prototype that has some required dependencies. The principle of dependency injection would tell us that instead of ModuleC being responsible for loading ModuleA and ModuleB, those should be injected into it somehow. Broadway is a fantastic library to help with this.

broadway

At it's core, Broadway provides a plugin architecture for applications, and a consistent way to manage and add functionality. It also gives us a nice platform for dependency injection, and inversion of control, letting the modules alter and build on the application instead of the application being responsible to build everything and pull in your modules' functionality. If you're interested in this concept, this article from the Nodejitsu blog is super informative.

So, let's start with a basic Broadway application, and load up a plugin that we'll define below.

var broadway = require('broadway'),
    app = new broadway.App();

app.use(require('myposse'));

app.init(function(err) {
    // we're all setup, gtg
});

A basic Broadway plugin might look something like...

// myposse.js

var MyPosse = exports;

MyPosse.name = 'myposse';

MyPosse.attach = function(options) {
    var app = this;

    // here we can add some functionality to the app
    app.posse = function() {
        console.log("my posse's on broadway");
    };
};

MyPosse.init = function(done) {
    // handle any asynchronous initilization
    done();
};

RIP MCA. Inside our attach function is where we can pull in our related modules, and expose them to the application. Notice how we're calling the result of the require statement of each module, passing in the Broadway application, and setting that onto the application itself.

MyPosse.attach = function(options) {
    var app = this;

    app.ModuleA = require('module-a')(app);
    app.ModuleB = require('module-b')(app);
    app.ModuleC = require('module-c')(app);

};

We would want to rework our above example of ModuleC to allow for this change, which also lets us remove the require statements for ModuleA and ModuleB, and pull them in as dependencies from the app object.

module.exports = function(app) {

    var ModuleA = app.ModuleA,
        ModuleB = app.ModuleB;

    var ModuleC = function() {
        this.myB = new ModuleB();
    };

    ModuleC.prototype = {

        /** amazin' function! */
        amazinFunction : function() {
            if(ModuleA.isAmazin(this.myB) {
                this.beginAwesomness();
            }else {
                this.sadPanda();
            }
        },

        beginAwesomness : function() { /** awesome stuff */ },

        sadPanda : function() { /** sad stuff */ }

    };

    return ModuleC;

};

With Broadway you can organize your application's modules and expose their functionality to the application via plugins. I've found it a great way to organize services, models, and other application resources, and expose them to the application without coupling them directly to eachother via require statements. There's definitely a place for modules that are independant enough to be require()'d at will, but I've also found that there's a place for application specific modules that are best managed at an application level.

There's a lot more Broadway has to offer (such as application events), so check it out if you're building large applications on node.js.

node.js and circular dependencies

Tuesday May 8, 2012
By Brad Harris

Circular Dependencies in modules can be tricky, and hard to debug in node.js. If module A requires('B') before it has finished setting up it's exports, and then module B requires('A'), it will get back an empty object instead what A may have intended to export. It makes logical sense that if the export of A wasn't setup, requiring it in B results in an empty export object. All the same, it can be a pain to debug, and not inherently obvious to developers used to having those circular dependencies handled automatically. Fortunately, there are rather simple approaches to resolving the issue.

example.broken() === true

Let's define a broken scenario to clearly illustrate the issue. Module A delegates to an instance of Module B to do some important stuff().

Module A

var B = require('./B'),
    id,
    bInstance;

var A = module.exports = {
    init : function(val) {
        id = val;
        bInstance = new B();
        return this;
    },

    doStuff : function() {
        bInstance.stuff();
        return this;
    },

    getId : function() {
        return id;
    }
};

Module B

var A = require('./A');

var B = module.exports = function(){
    return {
        stuff : function() {
            console.log('I got the id: ', A.getId());
        }
    };
};

Tie them together

require('./A.js')
    .init(1234)
    .doStuff();

With this you'll end up with an error:

TypeError: Object #<Object> has no method 'getId'
    at Object.stuff (/Users/bharris/workspace/circular-dep/B.js:7:36)
    at Object.doStuff (/Users/bharris/workspace/circular-dep/A.js:18:13)
    at Object.<anonymous> (/Users/bharris/workspace/circular-dep/test.js:4:3)

The issue is that when A is required at the top of B, it ends up being an empty object, which doesn't have a getId method.

example.solutions().length === 2

I'll explain two simple solutions to this issue:

delay invocation of dependency until runtime

If we move the require statements to where they are needed at runtime, it will delay the execution of them, allowing for the exports to have been created properly. In this example, we can get away with simply moving the require('./B') statement.

Module A

var id,
    bInstance;

var A = module.exports = {
    init : function(val) {
        id = val;
        bInstance = new require('./B')();
        return this;
    },

    doStuff : function() {
        bInstance.stuff();
        return this;
    },

    getId : function() {
        return id;
    }
};

This feels like a bit of bandaid to this particular problem, but perhaps is the right solution in some cases.

replace circular dependency with dependency injection

The only dependecy that B currently has on A is an id property it needs access to. We could just pass the id into the constructor of B, but let's assume A is more significant to the operations B must perform, and a proper reference is required. If we inject that dependency we'll allow for a loose coupling between the two modules, and have a slightly more elegant solution. Zing!

Module A

var B = require('./B'),
    id,
    bInstance;

var A = module.exports = {
    init : function(val) {
        id = val;
        bInstance = new B(this);
        return this;
    },

    getId : function() {
        return id;
    },

    doStuff : function() {
        bInstance.stuff();
        return this;
    }
};

Module B

var B = module.exports = function(val){
    var dependency = val;
    return {
        stuff : function() {
            console.log('I got the id: ', dependency.getId());
        }
    };

};

#winning

DependencyInjection
    .merge(LooseCoupling)
    .attach($);

I put my $ on dependency injection and loose coupling.

markdown powered blogs

Saturday April 14, 2012
By Brad Harris

Switching from a complex blogging platform to a lightweight, file-based blog is something of a trend amongst web developers lately. I chalk it up to our love of simple solutions, and a preference of interfacing directly with a file-system. I much prefer to open up SublimeText2, go into distraction free mode and create a markdown file for a new article. For me it's a smaller barrier of entry to writing than logging into Worpress and gathering my thoughts in a <textarea>.

what's out there

There are some great options out there for markdown based blogs. My preference is towards node.js, and Wheat (created by Tim Caswell) as a platform for howtonode.org is one of the more popular solutions in that category. Blacksmith is another great solution, created by nodejitsu. Both are interesting and powerful solutions, but weren't exactly what I wanted.

javascript is easy

I wanna be in control of the urls for articles, use the templating engine I prefer, and have some fun writing javascript. I also want to be able to start my blog up locally on a node http server to tweak it and test it, and not have to generate the static site to view every change. For the live site, I want to just clone a git repo on a server, and run > node generate.js to create a static site for Apache to serve. So I did, it was fun. Feel free to check it out, maybe fork it and see what you think.

i can haz dropbox blog?

Check out what Joe Hewitt is doing to integrate Dropbox into his blogging solution. I dig it.

node.js clusters

Wednesday April 4, 2012
By Brad Harris

When it comes time to deploy a node.js application, you'll want to examine how you can benefit from your hardware and take advantage of multiple cpus. Node is single threaded, so having one process run your application on a server with more than one cpu isn't optimal. Fortunately, like many things on node, it's simple to do so.

Let's take the following example of a dead simple http server:

    require('http').createServer(function(req, res) {
        res.writeHead(200);
        res.end('this is dead simple');
    }).listen(3001);

You've got that saved in a file, let's call it app.js. You start it up...

    > node app.js

...and it's amazing, it writes out text to all those that visit your site, just like you want. It's become an overnight internet sensation, and now you want to know what crazy hoops you'll have to jump through to scale it up and take advantage of all the cpus on your server. Enter the cluster module.

We'll create a new file that we'll use in production to launch our application. Let's call it cluster.js.

    var cluster = require('cluster');

    if (cluster.isMaster) {
        //start up workers for each cpu
        require('os').cpus().forEach(function() {
            cluster.fork();
        });

    } else {
        //load up your application as a worker
        require('./app.js');
    }

When you start your app now...

    > node cluster.js

...node will recognize that the cluster is the master, and then you simply fork the cluster for each cpu you have. Those in turn will start up, and those workers won't be the master, so they'll just load up your app.js and start up a process for each cpu.

But wait, doesn't each worker have to listen on a different port?

"The cluster module allows you to easily create a network of processes that all share server ports."

One TCP server is shared between all workers, so they can all be listening on the same port.

Awesome, you're now handling loads of traffic, but after a day you realize two of your workers died because you had an exception being thrown in that complex codebase of yours. How can you make sure you keep them running?

    if(cluster.isMaster) {
        //start up workers for each cpu
        require('os').cpus().forEach(function() {
            cluster.fork();
        });

        cluster.on('death', function(worker) {
            console.log('worker ' + worker.pid + ' died');
            cluster.fork();
        });
    }

Listen for the 'death' event on the cluster, and just fork a new worker if one dies. Simple huh? Keep in mind, every worker is it's own process, therefor they don't share memory.

Review: Yahoo! User Interface Library 2.x Cookbook

Wednesday April 20, 2011
By Brad Harris

I've had some time to really dig in to Matt Snider's latest book, Yahoo! User Interface Library 2.x Cookbook, and have some great things to say about it. I wanted to take a different approach to reading and reviewing this book, and hopefully it proves helpful to readers. I've been working on whoopdwhoop.com in my free time a lot lately, and normally as I'm developing front-end code using YUI, I reference their online documentation (which is pretty good IMO) when I have questions. I decided to just rely on this book for the past few weeks to really see how useful it was as a reference while developing. In short, it has been a great development companion. Let me explain...

I was working on adding some DataTable functionality for a client's site (Aeris Secure), and found the chapter in Matt's book to provide great examples and explanations for getting it going relatively quickly. He lays out multiple use cases for the DataTable, as he does so with just about all of the chapters, and that wide coverage provided a great reference as I found each example had additional insight into how to use the particular component of the YUI library. I think this approach will be a great way for beginners to ramp up to using the library, as they start fairly vanilla and basic, but as you progress the more advanced use cases and features are discussed. For a developer that is more familiar with the basics, they will quickly learn to jump a few sections in to each chapter to get to the meat of what they want to learn.

That's one example of how I found the book to be helpful in practice. If you want a solid picture of how to work with YUI, this book is great.

Latest Endeavor: whoopdwhoop.com

Sunday January 23, 2011
By Brad Harris

My wife and I have been chugging away on a new endeavor for awhile, and we finally got to a point where we could launch it live. In short, it's a currency free, creative marketplace, and it's called whoopdwhoop.com. It gives "artisans", or crafty people, a place to list their creations, and hopefully, a community where they can swap their creations with others all without exchanging any currency. This is facilitated through a pretty simple "whoop" (read point) based system. As people request a creation from someone, they pay them in "whoops", and then that person can use those "whoops" to request other creations. We haven't pushed much of a marketing campaign at it yet, in hopes to gauge initial feedback before doing so, and fix or improve whatever came up. We've done a fair amount of that so far, and are pretty happy with it's current state. Needless to say, we can't speak to if it will catch on and be the start of a thriving community, we'll have to wait and see.

While I don't think the majority of my blog's reader-base would be interested in using the site itself, I wanted to make a quick post to point out how the development of it has gone, which will hopefully be of more interest to those reading.

I built the site in about 4 or 5 months of actual heads-down, after-hours work. I have a day job, so this is just something I've spent nights and weekends putting time into. It's built on Zend Framework MVC, which I absolutely love. The UI is enhanced through YUI, which is another favorite library of mine. The database is MySQL, and I'm also using Doctrine ORM.

Zend Framework and Doctrine, in my mind, are a great marriage of libraries for PHP. Zend handles everything I've needed from an MVC, with the additional benefits of providing out-of-the-box API's for things like ACL, Auth, Caching, Emails and Logging. Doctrine does a great job at providing a stable and solid ORM, and a great means of managing updates through a simple migration strategy. The best part about finding a solid framework you enjoy working with, is you eventually end up with a great set of features you've built that can be dropped in to any project, giving you quite the head-start. When I started ( which was actually over a year ago, my motivation comes in spurts), Doctrine 2 was in development, but wasn't where it is now. I like the concept they've taken with the new version, but currently I'm using their 1.x version.

YUI is being used pretty sparingly right now. I think the only modules being used currently are containers for the dialogs, buttons, and menu. I need to give a shout out to the Minify library as well, which is handling the JS/CSS minification quite nicely.

I have some follow-up posts I plan on writing to go into more detail on some of the items and techniques I used in regards to things like Caching, but until I've had more of a chance to put the site through a ringer, I'll hold off. Anyways, if you're building a new site, looking for frameworks, I highly recommend everything I mentioned above.

YUI => jQuery?

Friday November 19, 2010
By Brad Harris

Recently a question was posted on Quora, "How could YUI3 improve its image compared to jQuery, MooTools, etc.?". John Resig, of jQuery fame, gave a great answer on his thoughts to the question. Nicholas Zakas responds with another great explanation of why he doesn't think the comparison is needed. I disagree with Zakas in regards to jQuery not being sufficient for "scalable web applications". Both have great points, and are worth a read if you're actively involved with frontend engineering.

YUI 2.8 Learning the Library book review

Saturday September 4, 2010
By Brad Harris

I've had a chance to read through the latest book on YUI, titled YUI 2.8 Learning the Library. The book was written by Daniel Barreiro and Dan Wellman, and was published by Packt Publishing. For the impatient that don't want to read the whole review, and want to get right to the goods, here they are. The book has great coverage of the YUI library, including all of the popular widget like Calendar, Container, Autocomplete, DataSource, DataTable and more. If you'ren new to YUI and looking for an overage and how-to for the library, this book would serve you well. If you're an experienced YUI developer, you probably won't get a whole lot out of this book that you don't already know, or couldn't gain through reading YUI's online examples and API.

If you read through this book in it's entirety, you'll come to understand the main reason I love YUI, that it's not just a collection of widgets and utilities. This book explains the full feature set of the YUI library, and you'll realize that it's the perfect foundation to build on top of. The author's do a really great job of showing in depth examples that teach you how the components work. I particularly liked reading the chapter on DataSource and DataTable.

If the online examples provided by Yahoo! leave you wondering how things are working, this book fills in those gaps. Most of the book is targeted to beginners and intermediate developers.

"YUI 2.8: Learning the Library" Free Chapter

Friday August 13, 2010
By Brad Harris

Grab a free chapter of the latest YUI book from Packt Publishing, "YUI 2.8: Learning the Library." The free chapter covers something we all use a lot, menus. I'm checking it out now, and suggest if you use, or are thinking about using YUI, you do the same since it's free.

I've been using YUI for about 4 years now, and love it. I love the solid foundation it provides for me to build my own interfaces on top of. I love the polished UI elements it provides as well. I'm looking forward to reading this book in its entirety. Check back soon for a full review of it.

First iPhone App - LDS Gems

Saturday May 8, 2010
By Brad Harris

Update: LDS Gems is no longer on the Apple App Store. http://gems.lds.org was not actively updated for a period of time, but is once again. I don't have plans to put LDS Gems back on the App Store.


After a bit of work, I finally got my first iPhone app on the App store. It's nothing extraordinary, but was a learning experience for the most part. It's called LDS Gems, and is an easier way to manage, read, and share the quotes and stories provided by the LDS church at http://gems.lds.org.

I used Titanium Appcelerator to build it, and was really impressed with how much easier it was to develop using Javascript as opposed to Objective-C. This is probably due to having quite a bit more experience with Javascript than the later, but I really enjoyed it and would recommend it to anyone wanting to dive into iPhone App development, but not ready to take on learning Objective-C.

Getting keycode values in Javascript

Wednesday September 16, 2009
By Brad Harris

I've had to work with getting user input values based off of the keycode from the event a few times, and figured I'd throw together some of that functionality in case anyone else is wrestling with this. Below is a simple "keycode" object that has a few utility functions, and maps of values to keycodes.

keycode = {

    getKeyCode : function(e) {
        var keycode = null;
        if(window.event) {
            keycode = window.event.keyCode;
        }else if(e) {
            keycode = e.which;
        }
        return keycode;
    },

    getKeyCodeValue : function(keyCode, shiftKey) {
        shiftKey = shiftKey || false;
        var value = null;
        if(shiftKey === true) {
            value = this.modifiedByShift[keyCode];
        }else {
            value = this.keyCodeMap[keyCode];
        }
        return value;
    },

    getValueByEvent : function(e) {
        return this.getKeyCodeValue(this.getKeyCode(e), e.shiftKey);
    },

    keyCodeMap : {
        8:"backspace", 9:"tab", 13:"return", 16:"shift", 17:"ctrl", 18:"alt", 19:"pausebreak", 20:"capslock", 27:"escape", 32:" ", 33:"pageup",
        34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up", 39:"right", 40:"down", 43:"+", 44:"printscreen", 45:"insert", 46:"delete",
        48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9", 59:";",
        61:"=", 65:"a", 66:"b", 67:"c", 68:"d", 69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l",
        77:"m", 78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v", 87:"w", 88:"x", 89:"y", 90:"z",
        96:"0", 97:"1", 98:"2", 99:"3", 100:"4", 101:"5", 102:"6", 103:"7", 104:"8", 105:"9",
        106: "*", 107:"+", 109:"-", 110:".", 111: "/",
        112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7", 119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
        144:"numlock", 145:"scrolllock", 186:";", 187:"=", 188:",", 189:"-", 190:".", 191:"/", 192:"`", 219:"[", 220:"\\", 221:"]", 222:"'"
    },

    modifiedByShift : {
        192:"~", 48:")", 49:"!", 50:"@", 51:"#", 52:"$", 53:"%", 54:"^", 55:"&", 56:"*", 57:"(", 109:"_", 61:"+",
        219:"{", 221:"}", 220:"|", 59:":", 222:"\"", 188:"<", 189:">", 191:"?",
        96:"insert", 97:"end", 98:"down", 99:"pagedown", 100:"left", 102:"right", 103:"home", 104:"up", 105:"pageup"
    }

};

Typically, you would have an event listener on an input that would call keycode.getValueByEvent(). You would have to pass in the event, (which is by default the first parameter passed into your event listener function). This code handles the shift key modifier and the value that results from using it.

Scoping Javascript closures in loops

Friday January 23, 2009
By Brad Harris

It must have been something I ate, cause this is like the third post in 2 days I think! This is a quick one, but super handy to know if you don't already. There is semi-common problem I run into, and it has to do with scoping of closures inside of loops. Lets get straight to the code so its easier to understand what I'm talking about:

<html>
<script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/utilities/utilities.js" ></script>
<script type="text/javascript">
    var values = [0,1,2,3,4,5,6,7,8,9];
    for(var idx in values) {
        //First Test - will have incorrent scoping
        YAHOO.util.Event.addListener(window, 'load', function() {
            YAHOO.util.Dom.get('wrong-scope').innerHTML += ' '+values[idx]+' ';
        });
        //Second Test - scoping will be correct
        YAHOO.util.Event.addListener(window, 'load', function(scopedValue) {
            return function() {
                YAHOO.util.Dom.get('right-scope').innerHTML += ' '+scopedValue+' ';
            }
        }(values[idx]));

    }
</script>

<body>
<div id="wrong-scope">
<h1>Wrong Scope</h1>
</div>
<div id="right-scope">
<h1>Right Scope</h1>
</div>

</body>
</html>

In this example, there is a simple array of ordered values, and then a loop over those values. For each iteration of the loop, there is an onload listener added that will dump that value into a div. You'll see the first loop always dumps 9, because the scoping is wrong when the closure executes, and the last time through the loop sets the scope of values[idx].

The second section does some unique handy-work to correct the scoping. A listener is added like before, but the closure is created in a specific fashion in order to get the scope to be the way we want at runtime. For the closure in the second section, we create a self-executing function, passing in a parameter that is the current value in our array of numbers. That function runs, and returns another function that does the appending to the div of the value. This second, inner-function is what will execute on page load. Because of the outer-function we immediately called, the variable passed into it, the current value from our array, will be available, and properly scoped for our inner-function.

scoping

This is a handy trick when you have a situation where you are looping over a collection, and are providing some type of callback/closure for each entry, but need some proper scoping.

Browser autocomplete and keyup events

Friday January 23, 2009
By Brad Harris

Update: This issue appears resolved in modern browsers, and was only noticed in IE7 and Firefox 3 (Linux & Windows)


Browser oddities are nothing new, but I came across one today that I haven't heard about before, and couldn't seem to find many comments about on the interwebs. To get to the gist of it, when the native browser autocomplete functionality pops up for a text input, it also triggers a keyup event for the input. I had some logic going on where I was firing an ajax lookup request as a user types in a value, and was waiting for a delay in their typing to fire the ajax request. I noticed I would often get two events fired at almost the same time. At first I chalked it up to oddities with setTimeout() not being completely accurate, but with more investigation, the native autocomplete that the browser supplies was the culprit.

To try this for yourself, here is the test code I was using:

<html>
    <script type="text/javascript">
        function handleEvent() {
            document.getElementById('keyup-test').innerHTML += document.getElementById('test').value + '<br />';
        }
    </script>
<body>
    <form action="">
    <div id="keyup-test"><h1>Test Keyup Event</h1></div>
    <input type="text" id="test" onkeypress="handleEvent();" value="bradharris" />
    </form>
</body>
</html>

You'll see the current value of the input written out into a div above the input on each keyup event. To get the autocomplete functionality of the browser working, just type in a value, and then submit the page by pressing enter when the input is focused. The browser will then have that entry in its history of values for that input, and will start firing the keyup an extra time when it finds a match and shows the autocomplete box. To turn it off, just add autocomplete="off" to the input tag, then it should only fire once per keyup. I'm pretty perplexed as to why this exists, and I've seen it in IE7 and Firefox3 (Linux and Windows). If anyone knows why its around, I'd love to hear.

Followup on YUI : getFirstDescendantBy()

Thursday January 22, 2009
By Brad Harris

Awhile ago I posted on an additional function for YAHOO.util.Dom called getFirstDescendantBy(). I was following the ticket submitted to the YUI Sourceforge tracker, and saw that it had been closed out, and that a new function called YAHOO.util.Dom.getElementBy() was added to fill this request. I decided to check out the newly available YUI source code on github, and noticed some nice enhancements. YAHOO.util.Dom.getElementBy(method, tag, root) is now available (not in the latest stable release yet though), and does what getFirstDescendantBy did, and in most cases its much faster. Great job to the YUI team!

Instead of taking a recursive approach to walking the graph like I had, YUI is just grabbing all the children by tag name, even if you don't supply a tag name (in this case it will use ''). This turns out to be much faster than the recursive approach for most cases. If you happen to be looking for an element in a very large dom tree structure, and that object is located early on in the tree, the new YUI approach will be slower than the recursive approach. Fortunately, when I say *"large" dom tree, I'm talking about a tree about 8 nodes deep, iterated 500-1000 times. Most of us don't work with sites displaying that much html on a single page, so its definitely not a concern in my book.

Digging in further, I noticed that the new getElementBy just delegates to YAHOO.util.Dom.getElementsBy(), which has now been improved to accept a number of additional parameters than what 2.6.0 has available. One of those is a boolean, firstOnly, which will stop after it finds the first match, and return it. It looks like there are also additional parameters for passing in an object to your apply method, and making that object the scope.

I'm excited about this change, and it means I will soon be able to use the native YUI function for what I needed. I'd suggest that anyone else that was using something such as getFirstDescendantBy() that I had shared look at switching once YUI releases the new function. Thanks again YUI.

Javascript widget approaches: Singleton vs Prototype

Tuesday December 23, 2008
By Brad Harris

Recently I've been doing some work setting up some standard javascript widgets for a web application I am working on. By widget, I'm referring to items such as javascript date pickers, tooltips, autocomplete inputs, etc. I'm building on top of YUI for this approach, but the principles I'd like to discuss are applicable to any library. YUI provides a fantastic javascript library, and a collection of widgets right out of the box. More than likely, as you add them to your application, you'll want to wrap or extend them in your own javascript implementations to get them functioning as desired. To accomplish this, I typically have taken one of two approaches, and these are the topics I'd like to cover. To provide a working example, I'll use a simple wrapper for a YUI Calendar widget that is linked to a text input, and opens by clicking a calendar icon.

image of a date picker widget

Prototype approach

This approach basically creates an instance of the javascript widget for each input field, and the javascript widget object utilizes the prototype definition so the internal functions can be defined once in memory. Below is an example of what a simple DatePicker widget that "wraps" the YUI Calendar widget, would look like:

function DatePicker(icon, field) {
    this.icon = icon;
    this.field = field;
    YAHOO.util.Event.addListener(window, 'load', this.initialize, this, true);
}
DatePicker.prototype = {

    icon : null,

    field : null,

    calendar : null,

    id : 'date-calendar',

    container : null,

    initialize : function() {
        YAHOO.util.Event.addListener(this.icon, 'click', this.click, this, true);
        this.renderContainer();
    },

    renderContainer : function() {
        this.container = document.createElement('div');
        this.container.style.display = 'none';
        document.body.appendChild(this.container);
    },

    click : function(e) {
        if(this.calendar === null) {
            this.renderCalendar();
        }
        this.calendar.show();
        this.positionCalendar();
    },

    renderCalendar : function() {
        this.calendar = new YAHOO.widget.Calendar(this.field+'-calendar', this.container, { title:'Choose a date:', close:true, navigator: true } );
        this.calendar.selectEvent.subscribe(this.populateDateField, this, true);
        this.calendar.render();
    },

    positionCalendar : function() {
        var position = YAHOO.util.Dom.getXY(this.field);
        position[1] = position[1] + 25;
        YAHOO.util.Dom.setXY(this.container, position);
    },

    populateDateField : function() {
        var date = this.calendar.getSelectedDates()[0];
        YAHOO.util.Dom.get(this.field).value = date.getMonth() + '/' + date.getDate() + '/' + date.getFullYear();
        this.calendar.hide();
    },

    hide : function() {
        if(this.calendar !== null) {
            this.calendar.hide();
        }
    }

};

The html for creating this widget is as simple as follows:

<script type="text/javascript">
    new DatePicker('date-icon', 'date-field');
</script>
<label>Date: </label>
<input type="text" name="date-field" id="date-field" />
<img src="images/calendar.png" id="date-icon" />

Some benefits to this approach are that the instance of the widget object has a direct reference to the input id and calendar icon id, and nothing has to be 'inspected' at runtime execution of the events. This leads to some cleaner code on a small level. It also has some downsides as we'll discuss below.

Singleton approach

The Singleton approach creates a 'singleton' wrapper object that creates ONE YUI Calendar widget that is re-used across all input fields. At runtime, the icon clicked on is used to determine which input field is in use through an extra attribute added to the icon image called 'data-field' that contains the id of the input it is linked to. This code would look as follows:

DatePickerSingleton = {

    calendar : null,

    id : 'date-calendar',

    container : 'date-calendar-container',

    activeInput : null,

    initialize : function() {
        var icons = YAHOO.util.Selector.query('.date-icon');
        YAHOO.util.Event.addListener(icons, 'click', this.click, this, true);
        this.renderContainer();
    },

    renderContainer : function() {
        var container = document.createElement('div');
        container.id = this.container;
        container.style.display = 'none';
        document.body.appendChild(container);
    },

    click : function(e) {
        this.activeInput = common.byEvent(e).getAttribute('data-field');
        if(this.calendar === null) {
            this.renderCalendar();
        }
        this.calendar.show();
        this.positionCalendar();
    },

    renderCalendar : function() {
        this.calendar = new YAHOO.widget.Calendar(this.id, this.container, { title:'Choose a date:', close:true, navigator: true } );
        this.calendar.selectEvent.subscribe(this.populateDateField, this, true);
        this.calendar.render();
    },

    positionCalendar : function() {
        var position = YAHOO.util.Dom.getXY(YAHOO.util.Dom.get(this.activeInput));
        position[1] = position[1] + 25;
        YAHOO.util.Dom.setXY(this.container, position);
    },

    populateDateField : function() {
        var date = this.calendar.getSelectedDates()[0];
        YAHOO.util.Dom.get(this.activeInput).value = date.getMonth() + '/' + date.getDate() + '/' + date.getFullYear();
        this.calendar.hide();
    },

    hide : function() {
        if(this.calendar !== null) {
            this.calendar.hide();
        }
    }

};
YAHOO.util.Event.addListener(window, 'load', DatePickerSingleton.initialize, DatePickerSingleton, true);

The html for creating this widget is as simple as follows:

<div class="code-highlight"><code>
<label>Date: </label>
<input type="text" id="date_field" />
<img src="images/calendar.png" class="date-icon" data-field="date_field" />

Results

After testing out each of these approaches using a range from 1 to 1000 inputs on a page, I noticed some interesting side effects. Both approaches load using almost the same amount of resources. You might think the Prototype approach would require more memory on page load to create each of the widgets for each input, but in reality, due to the prototype definition, the only additional memory needed for each widget is for the unique element id's stored as attributes. Each approach also uses a 'lazy loading' approach, that causes the Calendar widget to not be created until the user actually clicks on an icon. This is where the two approaches begin to differ.

The Singleton approach consumes a small amount of additional memory on the first click, as it creates the Calendar widget at this time. For subsequent clicks the memory stays the same, as the objects have already been created, and are just being re-used. A downside to this approach is that on page load, a javascript css selector query has to be executed to gather all date picker icons to set up click events for them. This 'can' be time consuming with a large number of elements (1000+).

The Prototype approach will consume additional memory for each new icon that is clicked, as there is a Calendar widget created lazily for each input at the runtime click event of the icon. From my simple tests, I saw an increase ranging from 51.2 kb to 358.4 kb for each additional widget instantiated (each new icon clicked). In contrast to the Singleton approach, on page load there is no css selector query to run in order to attach the click events, as the element ids are already in memory from the instantiation of each 'wrapper' (DatePicker) object. This saves the possibly heavy css based query, but adds an initialize function for each input to the page load, which can be time consuming as well.

Recently I have been using the Singleton approach for creating widgets where it is possible, as I believe it scales better, and avoids the problem of memory increasing as users go about using the application. This can be accentuated even further when page life cycle is long such as in the case of single page web applications. I found this little exercise interesting in my own work, and hope it is informative for some other people out there. I'd love to hear any comments regarding this from everyone out there.

slikcalc 1.1 release

Thursday September 11, 2008
By Brad Harris

I've just released a new build of slikcalc - javascript calculator library that includes a few small bug fixes, and some shortcuts to the API. The new API for creating calculators looks as follows:

var columnCalc1 = slikcalc.create('column', {
    total: { id: 'cc-1-total' },
    registerListeners: true,
    calcOnLoad: true
});

as opposed to:

var columnCalc1 = new slikcalc.ColumnCalc({
    total: { id: 'cc-1-total' },
    registerListeners: true,
    calcOnLoad: true
});

Its a small change, but I think it's easier to use. Of course, the old way will still work, so existing code will not break with the addition to the API. Some other additions include a new, fully commented debug version of the code, along with using YUI compressor for the minified version, which shaved off a few kb from previous versions. Full documentation is also included in the download. Take a look and feel free to comment with any feedback.

Google Chrome - Holy Smokes

Wednesday September 3, 2008
By Brad Harris

The cats out of the bag, Google released their new browser, Chrome. I was pretty excited about the new features that this browser would include, some of which are a brand new Javascript VM called V8, along with using Webkit for the rendering engine. The fact that each tab in the browser is its own process is also awesome news for web developers. I decided to take a try using it to run the web application I develop at my job, which is a large Case Management System by Justice Systems.

I decided to pick a fairly rich page with lots of content and javascript for the benchmark. This page has multiple tabs, and updates a client side data model as the user edits it. As far as page load times go, IE 7 and Firefox 2 were both right around 1.2 - 1.3 seconds just to render this page, and parse the javascript. Chrome comes in at 663 milliseconds, about 50% faster.

The next test I performed was toggling between tabs (YUI tabs). This toggling also involves some front end validation along with storing and retrieving of client side data, so I figured it was a pretty good use case for testing out the new Javascript engine. IE 7 comes in at an average of 123 milliseconds to switch tabs, Firefox 2 at 143 milliseconds, and Chrome blows them away at 20 milliseconds.

With Chrome, Google is stating that the browser is a viable platform, which is great news for web developers who have started to see the limitations of current browsers. It makes sense that Google would be the one to push a browser like this, as many of their products are web-based, and rely on a performant browser. I can't help but think that they have been waiting to see if other browser vendors could step it up, but eventually just decided go ahead and get er dun' themselves. Way to go Google, this is great news for users and developers.

Teaching an old Framework new tricks!

Friday August 29, 2008
By Brad Harris

In summary, I want to discuss an alternative approach for developing a rich, dynamic UI using Struts1. The basic approach is:

  • Java Object to JSON string
  • JSON String consumed by Javascript
  • Manipulate UI, update Javascript model
  • On submit of form serialize Javascript model to JSON string
  • Set value of hidden input to JSON string
  • JSON string to Java Object on server side

Modern web development frameworks have come a long way, in almost every language. Many of the current popular frameworks have integrated widgets or processes for building rich ajax powered UI's with little hand-rolled code. This makes developing those applications faster and easier. Unfortunately, we can't always use the latest and greatest new frameworks as developers.

While working on a J2EE web application that was started over 5 years ago, I've learned a lot about how frameworks have evolved since then. When this project was started, Struts 1 was very popular, and a proven framework, so was naturally adopted for the front end. Over time, many things were built to integrate with Struts 1 and provide custom functionality that was required. This makes it very difficult, and highly improbable that a new front end framework can be swapped in due to the time and money that would have to be invested. At some point that may be a necessity, but until then, you have to work with what you have.

Building a rich UI using ajax in Struts 1 is ... interesting. Sruts1 is very form centric, and all of your form inputs in your UI map directly back to some field on your Java form object in one way or another. This makes it tricky to provide a flexible data structure for a rich UI that may be adding or removing elements. Try adding/removing elements to your page dynamically, and having them map back to your Struts1 Form in a clean way and you'll see what I'm talking about. A recent approach I took to tackling this situation was to depend very little on the framework.

Lets say I have a Java object graph I want to load into some front end javascript model to work with in the UI. I can fetch this asynchronously as the page loads as a JSON payload, or just dump it to the page into the appropriate place so my javascript consumes it. Either way, I need to make sure its painless to convert this data structure to a JSON string, or create it from a JSON string. This will make passing it back and forth from the server side to the client side much easier.

I can then use this as my front end data model to display, change, remove and add data. When I'm ready to commit my changes, I then have to get that back to my server side Java action. Obviously I could also make the persistence portion asynchronous as well, but sometimes thats problematic, as you may have a lot that goes on in the backend and the rendering of a new page (security, alerts, etc.) that you would have to replicate if you were to do this asynchronously. To keep everything working as normal, one approach is to take your javascript data graph, and serialize it into a json string and set it into an html hidden input. This input can be mapped back to your Struts form, so back in your action you have a json string you decode and create the appropriate Java objects from. I've found this to be a very useful approach when trying to build a very rich UI on top of an older framework. In summary, here are the steps followed:

  • Build your data as Java objects that can be serialized into JSON, and created from a JSON string.
  • Consume the JSON data into your javascript and work with it as needed in the front end.
  • On submit of the form, serialize the Javascript object into a JSON string and set it onto the value of a hidden input
  • Get the value of the hidden input on the server side as your framework supports, and convert the JSON string back to your Java objects

Javascript getFirstDescendantBy()

Wednesday August 20, 2008
By Brad Harris

Update: A new native YUI function is in the works, and does this job better


Recently I was working on optimizing some javascript, and found a slow area that was trying to find the first focusable input in a certain area of the page, and it was taking anywhere from 100 - 500 milliseconds, depending on the size of the DOM tree in that element. After digging into it, I noticed it was using the YAHOO.util.dom.getElementsBy() method, which basically had to walk through the whole DOM tree in this case, testing each node against the boolean method passed in. After calling that, it would then return the first, if any, element that getElementsBy returned. Obviously this was a bad approach, as after you find the first match, there is no need to go further.

I did a little research, and saw that this had come up in a thread on the YUI group. I ended up writing a small method to fill in this functionality I wanted out of YUI, called getFirstDescendantBy(rootEl, method). The function takes a root element, or string id of that element, and then a function to test each element against that has the element being tested as the only input. This function passed in should return a boolean, and is similar to the way the YUI dom function getElementsBy() works. Hopefully this will help out some people in similar situations.

function getFirstDescendantBy(rootEl, method) {
    var root = typeof rootEl === 'string' ? document.getElementById(rootEl) : rootEl;
    var firstDescendant = null;
    var children = root.childNodes;
    for(var idx in children) {
        var child = children[idx];
        if(child.nodeType === 1) {
            if(method(child)) {
                firstDescendant = child;
                break;
            }else if(child.childNodes.length > 0) {
                var recursiveResult = getFirstDescendantBy(child, method);
                if(recursiveResult !== null) {
                    firstDescendant = recursiveResult;
                    break;
                }
            }
        }
    }
    return firstDescendant;
}

Back to Firefox 2

Wednesday July 23, 2008
By Brad Harris

If you're like me, you use Firebug a lot, like, all day long. Long gone are the days of resorting to alerts. The worst I'll fall back to is using the YUI logger for IE.

I've recently been having a lot of issues using Firefox 3, and Firebug. Firefox 3 has been pretty consistent at crashing a few times throughout the day. Firebug 1.2 has recently been causing me more and more troubles, to the point where I can't get it to not stop at breakpoints that I've removed, or it stops at my breakpoint, but doesn't let me play it through or debug, or remove the breakpoint, because it doesn't show up as being registered.

I'm sure these are hiccups with the new version of Firefox 3, but it is pretty disruptive to me as I'm developing. I reverted back to Firefox 2 and an older version of Firebug until they get this sorted out, which I'm sure will be soon. For anyone looking, you can find old versions of Firefox on FileHippo, and past versions of Firebug from the normal download site.

Complex Javascript Event Handling: EventMediator

Wednesday July 16, 2008
By Brad Harris

A large enterprise sized project I work on uses YUI library extensively, and events are a huge part of the rich front end we're developing. What you start to learn quickly about UI events, is that dependencies between different events start to get very complicated very fast. When A depends on B, but B needs to wait for C and D and E to finish, but E needs to wait for F to finish, you have a complex situation on your hands. Up until recently we were able to rely mostly on just using CustomEvents in YUI to handle this for us.

Where that starts to break down is when you have one event, A, that is dependent on multiple other events, B, C, D. You now have to manually keep track of what has fired, and make sure you don't fire that A until B, C and D have all fired. With very little code, here is a simple class that can be used in conjunction with YIU CustomEvents. It will handle the 'book-keeping' of firing what you want when all the events you have designated fire.

EventMediator = {

    addActivationRecord : function(record) {
        record = record || {};
        var that = this;
        for(var idx in record.events) {
            var eventRecord = record.events[idx];
            if(eventRecord.event !== null) {
                eventRecord.fired = false;
                eventRecord.event.subscribe(function(scopedEvent) {
                    return function(e) {
                        scopedEvent.fired = true;
                        that.fireActivation(record);
                    }
                }(eventRecord));
            }
        }
    },

    fireActivation : function(record) {
        var fired = true;
        for(var idx in record.events) {
            if(record.events[idx].fired === false) {
                fired = false;
                break;
            }
        }
        if(fired === true) {
            record.activate.call(record.scope);
        }
    }

};

Using the EventMediator would look something like the following:

EventMediator.addActivationRecord({
    events : [
        { event : myObj.someYUICusomEvent },
        { event : myObj.anotherYUICusomEvent }
    ],
    activate : myObj1.myActivationCallback,
    scope : myObj1
});

It's pretty straightforward I think. You call addActivationRecord, passing in an array of objects, whose 'event' property points to a YUI CustomEvent. You also provide an activate callback method, and give it a scope in which to call the method. For my purposes so far this has worked pretty well, although I'm sure it could be built up to be much more robust. Hope it helps someone out!

Format Currency in Javascript (simplified)

Tuesday April 22, 2008
By Brad Harris

While working on slikcalc, I was trying to find the easiest way to format a number for currency. I had found some implementations that were pretty complex, using regex and absolute values, and thought there had to be a simpler way. This is what I came up with and it works in all the browsers I've tested (IE 6/7, Firefox 2 (windows & mac), Opera 9 (windows and mac).

function formatCurrency(num) {
    num = isNaN(num) || num === '' || num === null ? 0.00 : num;
    return parseFloat(num).toFixed(2);
}

Just thought I'd share for anyone working with something similar.

Slikcalc - Easy Javascript Calculations

Tuesday March 18, 2008
By Brad Harris

Slikcalc - Easy Javascript Calculations

I've put together a small javascript library that greatly simplifies creating dynamic javascript calculators. It works great for just about anything, ranging from calculating columns of values, to a complex custom formula. You can even write your own calculators and plug them into the framework with little effort. Calculations update automatically as the user types in their values.

Check out the details on the library, and download it from github

var columnCalc1 = new slikcalc.ColumnCalc({
    total: { id: 'cc-1-total' },
    registerListeners: true,
    calcOnLoad: true
});
columnCalc1.addRow({ id: 'cc-1-1' });
columnCalc1.addRow({ id: 'cc-1-2' });
columnCalc1.addRow({
    id: 'cc-1-3',
    checkbox: { id: 'cc-1-3-c' }
});

A few key features of Slikcalc:

  • Slikcalc works with popular Javascript libraries, including YUI, jQuery, Dojo, Mootools and Prototype. Adding support for new libraries is very simple as well.

  • Slikcalc handles attaching your event listeners for when the users type in values, click checkboxes, and when the page loads.

  • Slikcalc provides a simple interface for chaining multiple calculators so one can fire another, and so on.

Simple jQuery image rollover script

Saturday March 8, 2008
By Brad Harris

Just a simple script I use to automate image rollovers that may be of use to others. Just include this javascript:


UPDATED: I felt motivated to simplify this even more according to many of the comments below. This takes advantage of html5 data attributes instead of a custom one, and eliminates the need for a special hover css class. It also eliminates the need for a temporary variable to store the current image in by using a 'tmp' attribute, and then removing it when finished. It also preloads the images for the rollover.


$(function() {
    $('img[data-hover]').hover(function() {
        $(this)
            .attr('tmp', $(this).attr('src'))
            .attr('src', $(this).attr('data-hover'))
            .attr('data-hover', $(this).attr('tmp'))
            .removeAttr('tmp');
    }).each(function() {
        $('<img />').attr('src', $(this).attr('data-hover'));
    });;
});

This should be used with an img element as follows:

<img src="first.gif" data-hover="second.gif" />

Original code:

$(function() {
    $('.rollover').hover(function() {
        var currentImg = $(this).attr('src');
        $(this).attr('src', $(this).attr('hover'));
        $(this).attr('hover', currentImg);
    }, function() {
        var currentImg = $(this).attr('src');
        $(this).attr('src', $(this).attr('hover'));
        $(this).attr('hover', currentImg);
    });
});

This will pick up an image that looks as follows, and setup the rollover image:

<img src="first.gif" hover="second.gif"  class="rollover"/>

Combine your JS and CSS files with pack:tag

Friday February 29, 2008
By Brad Harris

Recently I needed to combine a whole heap of javascript files into a few files for performance reasons. On this particular project, we have a very large number of custom widgets we've written to extend the awesome YUI library. Keeping our javascript in small, modularized files is great for development and maintenance, and debugging. It does however cause issues when the client has to download close to 100 small < 1kb files. Enter pack:tag, an open source jsp tag library for combining javascript and css written by Daniel Galán y Martins. Its as simple as including a jar, adding the tld and properties files, then using it on your pages.

pack:tag is a JSP-Taglib that minifies, compresses and combines resources (like JavaScript and CSS) and caches them in memory or in a generated file. It works transparent to the user/developer and the compressing-algorithms are pluggable.

So far its worked great, and the reduction in the number of files, along with filesize by using the built in minify option has been a huge benefit. When I need to debug, its as simple as setting an enable flag to false, and I now have all the individual files at my disposal. If you're developing in Java-land, and need to combine your js/css files, I strongly recommend checking out this great open source tag library.

pack:tag

Ajax requests when users stop typing

Sunday October 7, 2007
By Brad Harris

I was tackling a problem the other day related to triggering ajax requests as a user was typing in an input field. Sometimes you can just fire off the request on the blur event, but other times you want to fire it off from a keypress event. Sending xhr requests on every keypress can quickly overload your server and/or database. More often than not, if a user is typing, you can wait until they are done, or for a pause in their button mashing to send the request. This saves your server from getting hammered by un-needed requests, but still gives the user the experience desired.

A simple approach to this is wrapping your method that handles the particular ajax request with another simple method that records the time when they key was pressed, and queues up the ajax request method using setTimeout. Here's an example below:

Example = {

   interval : 1000,

   lastKeypress : null,

   interceptKeypress : function() {
      this.lastKeypress = new Date().getTime();
      var that = this;
      setTimeout(function() {
         var currentTime = new Date().getTime();
         if(currentTime - that.lastKeypress > that.interval) {
            that.sendRequest();
         }
      }, that.interval + 100);
   },

   sendRequest : function() {
      //Perform xhr request
   }

}

The Example.interceptKeypress() method now becomes what you tie the keyup event of your text input to instead of going straight to the Example.sendRequest() method. The current time is recorded, and then Example.sendRequest() is queued up using setTimeout() and a closure to handle scoping and ensure that enough time has passed since the last keyup event (100 ms is added to the current time as a buffer).

This approach can easily be added onto existing event handlers if you find you're sending too many requests in particular situations, or for any type of event handling where you want to limit when/how often it is fired. Hope this benefits some people!

Rich Web Experience 2007

Friday September 7, 2007
By Brad Harris

I was lucky enough to be able attend the Rich Web Experience this year, put on by NFJS. We're on the 2nd day of the conference, and so far its been great. I got to attend a great presentation by Greg Murray on jMaki. Those guys are doing some interesting work on that project that seems to wrap up a number of js frameworks pretty well, and provide a common api/interface for using them in conjunction with eachother.

Other highlights of day 1 were Douglas Crockford's presentation on Javascript: The Good Parts, and his keynote on The State of Ajax. Its great to get to hear from someone who has a lot of personal experience in the history of the language and get his insight. So far its been great, and I'm looking forwad to day 2!

Javascript developement for Enterprise Applications

Friday June 29, 2007
By Brad Harris

I've had a few conversations with friends and co-workers about this very topic. My day job consists of working on a large Enterprise Application running on a Java platform. My evenings are mostly spent (sometimes at my wifes disapproval) working on smaller websites and projects for clients in PHP. Javascript is used fairly heavily in both scenarios, but what I've noticed over time is that how I develop in the different situations varies quite a bit.

For smaller sites I really enjoy using the jQuery framework, mostly because of its small footprint, and ease of use. At my day job our own Javascript framework is backed by YUI, which I also really enjoy working with. YUI is very well suited for us there as it provides great building blocks for creating your own components (not that jQuery doesn't, but theres a lot of basic components you can build off of in YUI that are only available as 3rd party plugins to jQuery). That being said, when developing different components on an Enterprise Application I get a chance to create something that can be utilized across a large variety of pages, and more often than not, used in slightly different ways. This leads to writing Javascript components in a contained, object-oriented fashion. While I do this as well for smaller sites I work on, without the vast number of pages that a large Enterprise Application has, it usually isn't very beneficial to create a highly configurable component that can be used in multiple different scenarios and manipulated countless different ways. Its never bad to create something like that, but the cost of time isn't always worth it for small sites.

A couple of things that I've come to notice that have really helped me create Javascript components that are highly adaptable and easy to re-use in different scenarios are as follows:

  • Make attributes and parameters configurable through a configuration object. I can't count how many times I've written something, thinking its only going to need attribute x and attribute y, so theres no need to stuff them into a configuration object, and shortly after come to realize I also need to add parameter z. So instead of having a constructor like this:

    function Component(one, two) {
      this.one = one;
      this.two = two;
    }

    you can save a lot of frustrations when coming back later and having to update all of your instantiations of that object to add a 3rd parameter by doing the following:

    function SweetComponent(config) {
      config = config || {};
      this.one = config.one || null;
      this.two = config.two || null;
    }

    Theres different ways of creating a constructor to set values from a config object, but thats the general idea, allowing you to add extra attributes without having to go back and fix all of your instantiations.

  • Provide event hooks. Another thing I've come across that I find helpful is providing hooks into different events that the component might perform. For example, one thing I've used a lot is a row selector component that lets you click a row to select a record. By using the YUI CustomEvent, and firing off an afterToggle event when the row has been clicked and selected, it allows other components to tap into that, and perform anything they need without having to manipulate the row selector component at all. Providing these hooks can be done different ways, and using YUI CustomEvents is just one of them. Other frameworks like Dojo offer an advice framework that I think is pretty nice as well, letting you wrap anything you might need. The disadvantage to this is, as a developer, it requires more intimate knowledge of the Objects and their functions, knowing where to put your advice. By writing your own custom events, and firing them off in the correct spots, someone can look at your object and see that there are only so many events to connect to, and pick the appropriate one.