Grow your CSS skills. Land your dream job.

Writing More Autonomous JavaScript

Published by Guest Author

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.

Comments

  1. Ryan Wheale
    Permalink to comment#

    You describe a plugin which automatically detects well-named address fields (awesome). Then you mention the single-field address at the end and all the problems with parsing an address. What gives? Does your plugin work with single-field addresses?

    • Permalink to comment#

      When it has to, yes. Since single-line parsing can get a little mucky, we don’t recommend it. But as the web moves forward, it’s something to work towards for a better overall UX.

    • Permalink to comment#

      Single-field address inputs simplify the user experience (see Google Maps). We might as well make steps in that direction. For example, why are we still asked for our credit card type at so many checkouts? The type can be deduced by simply looking at the digits of the card number. Applying this reasoning, we hope that autonomous scripts will help the developers and the site visitors have better experiences.

  2. Stopa
    Permalink to comment#

    I wonder if it’s possible to get something like this for global audiences. Won’t validate any way i try to write my home address (I live in Estonia)

  3. Bert
    Permalink to comment#

    Nice plugin, but not very usefull in Europe… (or outside the USA for that matter)

  4. I don’t need address verification currently, but I wanted to salute the good writing in this article. I wish all technical posts were this well written. Nice work!

  5. Permalink to comment#

    I wish it would work outside the USA!

  6. I like the concept. It’s interesting… recently I’ve been tasked with doing searches based on location and search term – all from one field. While it is horrible to program, who ISN’T doing that with google searches now? Anything fellow developers can submit that help with single line addresses will help immensely.

    Final thought: it may be cool to develop a unique UX where the user types in the UI one line, but the space next to it shows the parsing. If not correct, they can click in there and correct it. I think that could get confusing/cluttered, but I’d be interested to see someone try to design it. :)

  7. I’m all for the single-input, enter your address into this textarea approach. Exactly like how dates are better when they’re single fields.

    There are new addresses being created all the time, validating addresses against a database is expensive (in the UK). World-wide? Don’t bother. If you’re hooked up to a payment processor like PayPal that provides verified addresses, you don’t even need to ask for it.

    Alternatively it can be very simple to have no validation whatsoever:

    “Hey we’re glad you like our product! We need your address so we can send it to you, type it in here. We’re going to print this off and stick it onto your package exactly as you have entered it, so make sure it’s correct!”

    • Permalink to comment#

      Good example with the date field. Excellent one in fact. A well-planned date field will allow entry in a number of different formats and still parse it correctly. That means that the user doesn’t have to conform to the field. Instead, with a little bit of code (or even a lot, but just once) the field can conform to them.

      Certainly, the customer is responsible to enter their address correctly in the first place, no doubt about that. But, you can certainly go above and beyond (and be a hero) if they fat-finger an address and your website is able to recognize it immediately. We’ve all mistyped things before. If a customer orders a birthday present in plenty of time for it to arrive but it doesn’t because they messed up on their address, they’re still going to be disappointed with the whole experience. Why not do as much as possible to make their life easier. After all, a repeat customer is so much less expensive than a first-time customer.

      As for using Paypal address validation, that works well as long as you are processing a payment. If people are signing up for the local school newsletter, it’s still handy to validate the address to eliminate missent mail.

  8. Permalink to comment#

    Very useful, but unfortunately could not work outside U.S!

  9. Permalink to comment#

    I wish if could work in India. :(

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".