blog.andyhume.net

Thoughts and commentary on web development

Event delegation without a JavaScript library

Most of the articles and examples I’ve seen of handling events with event delegation use some kind of JavaScript library. Chris Heilmann’s much cited article uses the YUI library, and Dan Webb’s presentation at @media last month used the Prototype framework.

For those of us just building a bog standard JavaScript application without one of these fancy libraries, it’s worth taking a look at how event delegation works in the real world. It sounds more complicated than handling events in the standard way, but it really isn’t.

For those that haven’t come across the term before, event delegation refers to the technique of reducing the number of event listeners attached to the document by attaching just one listener to a containing element and testing in the handler where that event has bubbled up from.

Let me give you an example from the Multimap website. The main navigation on the site includes 6 links across the top, 4 of which require event handlers to alter the href attribute of the link when it is clicked. These 4 links have a class attribute of ‘bundle’.

Traditionally you might approach that situation in the following way.


var MMNav = {
init: function() {
var nav = document.getElementById('mainNav');
var links = nav.getElementsByTagName('a');
for ( var i = 0, j = links.length; i < j; ++i ) {
if ( links[i].className == 'bundle' ) {
links[i].onclick = this.onclick;
}
}
},
onclick: function() {
this.href = this.href + '?name=value;
return true;
}
}

There's a lot of overhead in the above code. First of all the getElementsByTagName loops through every DOM node in the mainNav element to find all the links. We then have to loop through them again manually to check the class names of the links. That's wasted CPU cycles at every stage.

How about if we could just attach one event listener to the mainNav element and then capture any click on the links within that?


var MMNav = {
init: function() {
var nav = document.getElementById('mainNav');
nav.onclick = this.onclick;
},
onclick: function(e) {
if ( e.target.className == 'bundle' ) {
e.target.href = e.target.href + '?name=value';
}
return true;
}
}

The simplicity and elegance of this should be pretty clear, but it has a number of performance benefits as well:

  • The less event listeners attached to a document the better. They all take up memory and in extreme circumstances can slow browsers down considerably.
  • There is much less code running on page load. One of the major issues with complex web applications is the wait on ‘load’ for JavaScript to execute and set up the document. The two loops in the first example are nowhere to be seen in the second example.
  • ‘Just in time’ execution. The second example does a little bit more work when the event handler is executed, but this is better than doing that work on ‘load’ when we don’t even know if the resulting handler is going to be executed or not.
  • It’s less code. Less code means less maintenance, and less bandwidth for both your web server and your users.

There’s one caveat to the above code. Getting the target element of the event is not always as simple as using e.target. In Internet Explorer you need to use e.srcElement. The easiest way of dealing with this is to use a small getEventTarget function. Below is what I use.


function getEventTarget(e) {
var e = e || window.event;
var targ = e.target || e.srcElement;
if (targ.nodeType == 3) { // defeat Safari bug
targ = targ.parentNode;
}
return targ;
}

Event delegation is a fairly well established practice when dealing with large numbers of event handlers (eg, a map with hundreds of points, all with click events attached), but in my opinion it should be the default way you go about adding and handling events. It’s a simpler, more intuitive, and more optimized way of dealing with a common pattern in client-side scripting, and it doesn’t require thousands of lines of a JavaScript library for it to be useful to you.

Multimap Twitterbot

A few people at Hackday presented hacks that use Twitter’s direct messaging API to interface with a third party Web Service. By far the coolest one was Colm and Richard’s that allows you to request data from eBay and Wikipedia as well as a host of useful information such as nearest cashpoints, cinemas, tubes, restaurants and many others.

Want an example? How about being able to text to Twitter closest atm from ec4a2dy, and get back a set of walking instructions for finding the nearest cashpoint. Pretty handy I would argue.

Want to know if there’s anything interesting round about? Try sending closest wikipedia from rome, italy and that should keep you going for a bit.

FireEagle

The hackday bot (not currently available for public use) uses Yahoo!’s FireEagle service to find out your current location so that you don’t have to send it to Twitter every time. This means if you can set up your GPS device or mobile to ping FireEagle your location every minute or so, you’ll never have to worry about where you are and what is around you again. You’ll simply text to closest pub, FireEagle will know where you are, let Multimap know so they can query their local information database and Twitter will send you back what you need. This is pretty astounding really, and I don’t know of another service right now that can offer quite the same kind of thing.

In my opinion FireEagle has some serious implications for the way location based services are going to work in the future, and I think what the guys built at hackday is an early prototype of what may be round the corner.

For added comedy value they also created a spoof iPhone ad to show off the Twitterbot in action. Is there no end to their creative genius?

Hackday was some days

It’s been a couple of days since hackday now, and I want to record my version of it. In summary it was the most fantastic weekend I could ever have hoped for. I had a feeling I would enjoy it, but it exceeded every expectation in every way.

And it was bloody hard work.

When Richard mentioned he had an idea for a hack that he wanted to do, I suggested we build it in Django. In hindsight that was a bit of hideous error, because it meant we didn’t have as many programmers at our disposal as we would if we’d chosen PHP. In fact, it meant we had me. And I’m not really a proper programmer. It was about 2am in the morning when I realised I might have bitten off more than I could chew, and that 2 hours was about as much sleep as I was going to get that night.

In the end we just about got away with it, and it allowed Rich to create a really fantastic UI and prepare a succinct presentation that really nailed the essence of what the app was all about.

Anyway, our hack was just one miniscule part of the whole experience. I’ve many memories and emotions from that long weekend. The incredible venue, with it’s panoramic views of London. The dark, misty atmosphere during arrival and the opening presentations. The venue being struck by lightening. People sitting under umbrellas as the rain poured through the open roof. Drinking Guiness with friends while watching hackers emerge from the West Hall into the foyer, dragging bean bags and laptops behind them. Lying on the floor watching Doctor Who with 300 hundred people applauding the Doctor’s blogging gag. The incredible, buzzing, crackling atmosphere of people coding through the night. John, Richard and Colm showing up at 10am on Sunday morning, and laughing “Have you two moved in the last 20 hours?” (we hadn’t). The crunch last few hours before presentations when we had to cut out half of what our hack did to get something to demo. Thirty minutes before Richard’s presentation when he turned to me and said, “It doesn’t work. It just doesn’t work!”. And finally, winning the Most Useful Hack award.

Without getting too emotional about things, it was one hell of a weekend which will stay with me for ever.

Hack on

It’s coming up to five O’Clock in the morning at Alexandra Palace. I’m still going stong to be honest, but I know I’m going to be frazzled in about 12 hours time.

There’s still a fair few fellow hackers up and working, but plenty of others scattered around the floor and the walls of the West Hall. Most trying to leverage two odd shaped bean-bags into various sleeping tools.

The atmosphere has been great all afternoon and evening. It was clear it was going to be a memorable day from the moment lightening struck the mast on top of the palace, accompanied by a huge explosion. The windows in the roof of the hall then proceeded to open and flood thousands of pounds of equipment with rain water. That was proceeded by a few hours of Wi-Fi free activities while BT fixed us up again.

Anyway, back to work for me. I’m building something. I’ve totally forgotten what it’s meant to do though. It’s got a database and a textfield I think. And some blue in it.

Update: It didn’t have any blue in it (that was a weird thing going on with Richard’s Mac Book screen), but it must have had something, as it was awarded the Yahoo! Most Useful Hack Award (or something like that). That was a bit of unexpected fun at the end of a very long and inspiring two days.

Hackday tomorrow

I’ll be up at Alexandra Palace tomorrow at the BBC/Yahoo! Hackday. I’m excited about it even thought I haven’t really got any plans or ideas for things to work on. The atmosphere at this amazing venue should be pretty special, and I can’t wait to see some of the cool stuff that is going to be created over the weekend.

Having said that, if anyone’s got a need for some web development skillz, or in-depth knowledge of mapping APIs, give me a shout. I’m probably going to have to get involved somewhere or they might just chuck me out.

See you there?

Multimap Open API

At the risk of going overboard with posts about maps, there’s a couple of other things that came out of Multimap this week that I want to mention.

Yesterday saw the release of the Multimap Open API, a JavaScript interface to much of Multimap’s core mapping functionality, and the power behind mapping on sites such as Yell.com.

The exciting thing about this version however is that it’s available to developers for use in mash-ups and other non-commercial projects. If you want to have a play with it, go sign-up for a key and take a look at some of the documentation.

In the final piece of map related news, John McKerrell, a lead engineer on the above mentioned API, has knocked together a neat bookmarklet which allows you to embed Open Street Map maps into the new Multimap website. This means you can get the richness of Multimap’s geocoding, routing, and useful information search on top of the OSM map tiles.

With Multimap being a sponsor of OSM, whose to say you won’t see this feature embedded into the site in the near future. It would be a great way to deliver the OSM concept, and indeed the data, to the mainstream.

Multimap raster maps

One of my favourite features of the new Multimap website is the different varieties of map data you can pull into the map viewer. Rather than just one layer of rendered vector data seen on many web-based maps, Multimap allows you to select from various other data sets depending on your location.

For example, if you’re a born-and-bred Londoner like me, you’re probably familiar with the magnificent A-Z style maps from Collins Bartholomew. These have always been available on the web from various sites, but seeing them in all their slippy glory on a high resolution monitor is a truly glorious sight.

My other favourite is the classic pink Land Ranger OS maps favoured by walkers and cyclists across Britain. Take a look at this area of the Lake District and try swapping between the data types to see exactly the kind of extra detail the raster maps give you.

To check if there are other map data-sets available in your area you can hover over the map button at the top left of the map. If data is available a small pop-out preview will appear which you can select to change the map style. The UI’s not perfect, and there’s probably a better way to expose this feature, but we’re working on that.

Presentational markup in HTML 5

I’ve been contributing to the W3C HTML Working Group working on the next version of HTML. I say contributing, I’ve found it tough enough keeping up with the pure volume of mail the group generates to make much of a contribution so far. Also, a lot of the initial discussions have been around some pretty high-level design principles which I’m leaving to the proper experts for the moment.

One thought-provoking topic that I have been following closely however is the <indent> vs. <blockquote> discussion. It’s not worth going in to the specifics of that conversation here, but you can find that in the archives if you want to follow it. What it has raised in my mind though is the question of using presentational mark-up in HTML.

Most of what I’ve learnt about Web Standards like XHTML and HTML teaches that mark-up is for giving structure and meaning to content, and that CSS is for presenting that content in a web browser or other environment of human consumption. However, history tells us that HTML is not used like that. The <blockquote> example is a good one — it’s regularly used to indent content in the middle of prose whether the content inside the <blockquote> element is really a blockquote at all.

The question is, would it be better for the Semantic Web if, instead of less knowledgeable page authors using <blockquote> incorrectly, an element like <indent> was created which allowed authors to simply indent content with no implied semantics?

I think most people’s reaction to this is: No, use CSS to indent the content. And that was my initial reaction as well. However, following the argument through I think I can see both sides of the argument. Why pollute the web with incorrectly used HTML when we can give authors that want it a semantic-free mechanism for indenting their content?

Flexing your apps

There’s been a bit of chat recently around things like Flash vs. Ajax, the The Ajax/Flash continuum, and other similarly stirring topics. I’d been thinking a little bit about the same sort of stuff myself, and indeed I weighed in at Jeremy’s blog in a rather non-committal fashion (if that’s possible), throwing the best-tool-for-the-job line out a few times.

Of course I’m significantly hampered when trying to make a point in this argument by the fact that I have got pretty much bugger-all experience when it comes to Flash. So last weekend I decided to address that problem a little bit.

Why would you want Flash?

I think the crux of Jeremy’s argument is that if you’re going to define JavaScript as a base-level technology for your application, then you’re not using JavaScript for what it’s best at: progressive enhancement of structural, meaningful markup. If progressive enhancement is not part of the plan at any stage then perhaps you should reassess why you’re using JavaScript in the first place?

This all ends up pointing me towards Flex, a powerful application development solution for creating and delivering rich Internet applications. At work that’s what I do—I create rich (often overly rich) Internet applications which require JavaScript for you even to be let in. It’s this situation where it appears that Flex might be the better option, so that’s what I downloaded and filled my weekend with.

First impressions?

Now, I’m the kind of person that gets very excited when I’m learning new skills and technology, so I need to keep some perspective when talking about Flex. Firstly, I’m having a good time learning it, and I’m impressed with the speed and ease with which you can actually achieve things. It wasn’t too difficult to put together a very basic and crappy RSS reader within a few hours (although why it’s 255K is a little odd), and the feeling you get when you realise it’s going to work in every browser on every platform without you even having to think about it, or even test it, is nice—to put it mildly.

Secondly, I’d somehow picked up the false impression that I had to use Adobe’s own tools to write my code in. This isn’t the case. I can write the XML, CSS and ECMAScript (all these standards!) in Textmate or any other editor I want. The only piece of Adobe software I’m using (aside from Flash in the browser of course) is a small command line script that compiles my application into a .swf file.

It doesn’t really feel like you’re entering a whole new world, and I got into some productive working habits quite quickly. There’s lots of concepts that those coming from browser based client-side development will be familiar with. It is of course all XML, CSS and ECMAScript, and the separation of content, style and behaviour is very much encouraged – if not enforced – within your applications code.

My problem with it?

I guess it sounds a bit naff; but it simply doesn’t excite me like the web does. In fact it doesn’t feel like part of the web at all. I want the semantics of HTML, the power and richness of microformats, and the potential for others to build on top of and extend my application with tools like Greasemonkey.

Flash by it’s compiled, closed nature doesn’t offer this and it’s hard to envisage a world where it ever will, despite Adobe’s moves to open it up with tools like Flex. I love that I can build Flash apps with standards like XML, CSS and ActionScript, and there’s no doubt that it takes away a lot of the pain of building web applications in the browser. It’s just that the end result never feels quite right to me.

However, now I’ve dived in a little I’m going to keep going. I’ve ordered The Complete Guide to Flex 2 and ActionScript 3.0, and I’m going to see what it takes to build the kind of applications I’m used to developing in JavaScript.

Most of all, I’ll now be able to join in the Flash vs. Ajax arguments with a little more professional integrity… or something.

Introducing RSLog

Remote Script Logging (RSLog) is a MIT Licensed, light-weight, and easily customisable script which allows you to catch and trace JavaScript errors occuring on your users’ machines by logging them back to your web server.

It is completely unobtrusive, adds only one reference to the browser’s global namespace, and weighs in at just 660 bytes when minified. Check out the demo page.

Using RSLog

To use RSLog simply include the core JavaScript file near the top of your document and begin logging by executing RSLog.start().

Of course the script needs to talk to something on the server. This can be in what ever language most suits your needs, but I have created a very basic PHP script that logs to a text file. The simplest way to start using RSLog is to download the gzipped archive (containing the JavaScript, PHP, and log file) and unzip to your web server.

Options

The RSLog.start() method excepts one optional argument. This is an object of configuration parameters as shown below.

  • suppress – Boolean to suppress errors being passed to browsers default error handling. Default: true
  • url – Full URL to send errors to. Default: /rslog/rslog.php on current host.


RSLog.start( { suppress: false, url: 'http://example.com/rslog/log.asp' } )

Supported browsers

To remain unobtrusive the script uses the window.onerror event handler to catch errors. This event is only supported by IE 4+ and Gecko based browsers, including Firefox, Camino and Mozilla. It is not supported by Safari or Opera, so you won’t be able to catch errors specific to those browsers.

andyhume.net

I build web sites and web applications. I currently work as a web developer at Clearleft in Brighton. I also write articles for magazines like .Net, and Computer Arts Projects. Sometimes I speak or give lectures on web design and development at universities and colleges. Get in touch.