Writing More Autonomous JavaScript

Avatar of Matt Holt
Matt Holt on (Updated on )

The following is a guest post by Matt Holt from SmartyStreets. Matt wrote to me about a new plugin they developed for verifying addresses, as he knew we’ve gone down the road of address trickery around here before. He wasn’t trying to promote their product so much as share a philosophy of plugin development, but I thought a guest post could do both. He obliged.

Street addresses are complicated. They should be easy.

They’re hard because:

  1. An address is not a single unit of data; it involves 2 to 6 different pieces
  2. Addresses are irregular and unpredictable (can’t be matched with regular expressions)
  3. An address can be sort-of valid without being fully valid
  4. Addresses are often the source of confusion for customers at checkout

At SmartyStreets, we addressed the problem (pun intended) by creating an event-based, highly autonomous jQuery plugin which hooks into an authoritative address API. We affectionately call it jQuery.liveaddress.

You can see it in action on this LiveAddress documentation page.

in-action

Actual implementations can be seen on ProCPR, Tortuga Rum Cakes, and other checkout, sign up, and contact forms. The end results make me want to see more autonomous jQuery plugins that just work without the need for meddling or configuration.

An autonomous script/app/plugin doesn’t need its hand held. It does its own thing, broadcasts what it is doing, and it just works. Here I’ll briefly focus on two aspects of the autonomous plugin:

  • Plug-and-play
  • Event-based

Plug-and-play

Unlike web apps, jQuery plugins need to adapt to their environment. jQuery’s selector engine, Sizzle, takes a lot of the pain away, but in our case, addresses can’t just be “selected.” They have to be identified, or “mapped.”

As such, jQuery.liveaddress is rather atypical: it isn’t just a function you can call directly on a set of matched elements, nor does it support chaining. To be truly plug-and-play, our plugin has to automatically find the elements in a form which pertain to address data: street, city, state, zip code, etc. The plugin scans your page for such elements and automatically arranges them into Address structures which are managed by Form objects. Everything is monitored internally for changes. We call this process “auto-mapping.”

Here’s how our old Javascript implementation was initialized. It didn’t have auto-mapping and it wasn’t very well engineered:

QadApi({
    timeout: 10,
    key: "HTML-KEY",
    busySubmit: false,
    autoClean: false,
    submitId: "submit",
    allowPost: false,
    properCase: true
    // ... other service-related configuration ...
  },
  {
    busyId: "QadBusy"
    // ... other CSS-related configuration ...
  },
  [
    {
      name: "Javascript Example",
      street: "street",
      city: "city",
      state: "state",
      zip: "zipcode"
    }
    // ... other addresses to be mapped, if any ...
  ]
);

Compare that with jQuery.liveaddress, which auto-maps:

var liveaddress = $.LiveAddress("YOUR-API-KEY");

See the difference?

On web pages with clear input name and id attributes, or even <label> tags and placeholder attributes, auto-mapping works remarkably well. You wouldn’t believe the gnarly-looking forms I saw during testing where name and id had nothing to do with the field itself, and of course, there were no <label> tags. (Designers: take note!) For such cases, we do provide a way for fields to be mapped manually, either during initialization or afterward, using selector strings:

liveaddress.mapFields([{
  id: 'billing',                // IDs are not part of the address
  street: '#street1',
  street2: '#street2',
  city: '#city',
  state: '#state',
  zipcode: '#zip'
}]);

Remember, if your plugin does or assumes something automatically, make sure the developer can override it and take control.

A jQuery plugin should not be like your kitchen table from IKEA (significant assembly required). Can’t it just work right out of the box? Whatever that means for your particular script, so be it: just don’t make me configure it whenever possible!

Event-based

Consider the likely case where you want to step in the middle of the address validation process and do something. If no events are raised, how do you know that an address was just validated? You’d have to go into the script’s source and finagle your own hack in the middle of it. Events are the elegant – and correct – solution to this.

We’re lucky that Javascript makes events such a routine thing! (Sort of.) Use events. Fire them off when cool (or un-cool) stuff happens.

jQuery makes events a breeze, and even maintains a reference to each bound handler. So while we’re all used to binding to events using jQuery, don’t forget to raise them also:

$(someElement).trigger(eventName, extraData);   // or use triggerHandler()

When raising events, be sure to pass in any data related to the event so that the handler has state (context).

jQuery.liveaddress raises up to 14 custom events during its lifetime. This has been immensely useful and powerful, as you’ll see below.

In fact, jQuery.liveaddress binds to its own events internally. This means you have the power to stop the process at any point and under any condition. For example, to prevent the user from submitting an address which is missing a secondary (apartment) number:

liveaddress.on("AddressAccepted", function(event, data, previousHandler) {
  
  if (data.response.isMissingSecondary()) {

    data.address.abort(event);      // reset some things internally
    alert("Don't forget your apartment number!");
  
  } else {
                
    previousHandler(event, data);   // continue the process

  }

});

Notice this on() function is invoked on the liveaddress object, and is not jQuery’s usual on(). When you bind a handler using jQuery’s on(), that handler gets fired after the ones previously bound. Since the plugin binds to its own events first and each handler chains to the next event, your own handler won’t be fired until the whole process is already complete.

To remedy, the custom on() function provided by jQuery.liveaddress will un-root the previous handlers, lay yours down, then plant the other handlers on top of it. This means yours is fired first. As you can see above, to continue the validation process, simply invoke the previous handler which is passed in as an argument. If you want the last word, just don’t call the previous handler.

6 address fields 1 address field

A quick aside before we wrap up. This is for the designers.

As has been said, street addresses are complicated. They require anywhere from 2 to 6 form fields, they’re frequently in a different order, everyone fills them out differently, and there are often mistakes during entry. Yes, verifying the input is important, but I’m not here to promote that. Instead, have you considered combining all the fields into a single one?

Users are more comfortable typing an address in a natural or intuitive format, as if they were writing it on an envelope. This tends to reduce input errors and makes for a pleasant experience.

While there are caveats with parsing address strings, it’s still a considerable improvement to your visitor’s experience. In this way, users can enter a freeform address and you can store the individual components if necessary.

Conclusion

We’ve looked at a couple different ways to make Javascript not like a high-maintenance girlfriend. Combined with semantic markup, scripts can be easier to use, smarter, and more intuitive. Ideally, they broadcast their actions by raising events, so that other code can know what’s going on and hook into them. The more automated your script is, the more robust it must be in hostile environments, like shopping cart checkout pages, or pages with highly dynamic content and features. Autonomous scripts adapt to their circumstances when possible, and fail gracefully if they can’t.