Professional jQuery

The Amazon page is updated with my name (even if the cover is still listing just the single author), so it’s as good a time as any to officially announce Professional jQuery, a book I co-authored for WROX over the past few months.

The project fell into my lap during a period in which I had a lot of time available to write, so it was a serendipitous opportunity that ended up working out perfectly.

When I came on board, the book was half finished and much of the structure was in place, so I was tasked with finishing out the remaining content and putting some polish to the existing chapters through the author review process. It was a lot of fun to do and exposed me to more depth in the jQuery API than I ever would have gotten simply as a consumer of the library.

In interviews now I tell candidates “pretend I’m Google if you have any questions about the jQuery API” when we’re going through code samples and I’m not really kidding.*

The book is broken into two sections, an introduction to jQuery/JavaScript basics and a section on Applied jQuery, which is where the “Professional” part of the title really comes into play. Most of that Applied jQuery section is my work and I’m very pleased with that content. I wrote a lot about jQuery and JavaScript best practices for speed and maintainability, introduced jQuery Templates, talked about the new Deferred object, went in-depth into unit testing with QUnit and did a long chapter on plugin development.

I learned a lot just writing it, so hopefully if you pick the book up you’ll learn a thing or two in reading it.


Speaking of interviews… while I’ve had some good luck hiring and am no longer a team of 1, I am looking for a senior JavaScript engineer to join my team. Why join me? I’m an awesome boss (even my interviews are fun) and the work is almost entirely focused on web application development using the latest/greatest web technologies. What more could you want?

Big Book Update: Now with 100% More Co-Authors

I just wanted to deliver on the book update I promised last week.Mobile Web App Cookbook is rolling now, with actual words being written. That’s pretty exciting for me.

What’s even more exciting is that we’re finally set with co-authors to do the technical chapters. I wanted to take a minute to introduce them, since they’re going to be the real stars of the show, providing the hands-on expertise the book is going to deliver. Me? I’m just a table-setter.

Anyway, here they are, the rest of the team (in order of appearance in the book):

Mike Morley

Mike is going to be doing chapters on the core technologies (HTML5, CSS3 and JavaScript.)

MIKE MORLEY is a freelance mobile user interface developer at 9eggs.com and has spent many years building web applications for financial institutions and digital media agencies. For the past few years he has specialized in developing mobile web applications for a range of clients from UK high street retailer New Look, the car manufacturer Ford and the UK lottery. When not building mobile web apps he may be spotted on the golf course or walking along the coast near Colchester (UK), where he lives with his wife Rachel, his young son and Chocky the dog.

Rich Freedman

Rich is going to be working on the jQuery Mobile section.

RICH FREEDMAN is a consultant at Chariot Solutions, where he works with a wide variety of technologies for clients ranging from startups to members of the Fortune 500. Rich has over 20 years of application development experience. He has been blogging about software development for several years, is a DZone MVP blogger, and has reviewed several books for Manning, including JQuery in Action and Roo in Action. When he’s not programming or reading or writing about programming, he’s probably in the kitchen, whipping up a gourmet vegan meal, while thinking about programming. Rich lives in Lambertville, New Jersey, a small and architecturally wonderful 18th century city.

Lee Boonstra

Lee is going to be working on the Sencha Touch chapters.

Lee Boonstra lives together with her partner in Amsterdam the Netherlands. While doing her study (Art & Technology) in 2004 she started her own web development company to continue to grow and learn new technologies. Right now her focus is more on mobile (web) apps. Her most successful app is available at the Apple Appstore and Google Chrome webstore: Spotlib.

In the last year of her study she worked for Accenture as a senior back-end (Java) developer for clients such as UPC and KLM/Air France.
After 3 years she decided to make the move to the front-end. “I think it’s advantageous to understand back-end technologies while working on the front-end. I’m a creative person and I like to have a nice workflow and see my changes directly on the screen.” In 2009 she started working as a front-end team lead for eFocus, one of the top 3 fullservice internet agencies in The Netherlands. “I’m working with a lot of (front-end) technologies & frameworks, and that is why I love my work so much: jQuery (Mobile), Mootools, Dojo, CSS3, HTML5, XML, SQL and recently Sencha Touch”. As a team lead she works on both mobile and web for middle to large scale clients, such as Deloitte, Heineken and Philips.

Beside technologies, Lee’s other passions are alternative music, attending concerts and festivals and (what she is famous in Amsterdam for) being a drag king performer and model. And let’s not get started about how extensive her videogame (console) collection is…

Using the Geolocation API

The following is probably the last long-form article you’ll see here for a while. I’m in full on book mode for the next couple of months, so I’m not expecting to be writing a ton here for the foreseeable future.

Anyway, the following is actually inspired by the kind of work we’re going to be doing for the book. I’m not actually doing any code-heavy writing for the book, so I wanted to get my hands dirty with this sort of content. It’s fun.

As an aside, I’ll have another (short) post about the book shortly. I’ve got a full allotment of co-authors and I’d like to give them, and the project, a little shine before I turn into a writing hermit.

And now… Geolocation


One of the most powerful aspects of mobile web app development is the ability to blur the line between the real world and the world on the screen. Allowing users to interact with physical places in novel ways is driving startups across the world and is infiltrating some of the most popular sites and applications on the web. Facebook, Foursquare, Twitter, Google+ and countless other services have built the idea of location into the core of their applications. You too can do the same in your mobile web app by taking advantage of the well-supported Geolocation API.

Whether it’s interaction with your own location based services or with a third party API, like the Google Maps API in use in this recipe, the journey begins with getting the user’s latitude and longitude.

In this article you’ll learn how to:

  • Use the W3C Geolocation API to get a user’s latitude and longitude
  • Smoothly handle devices without Geolocation support, providing a reasonable fallback for older devices
  • Use the Google Maps API to place a marker indicating the user’s location, labeled with a friendly place name

The Basics of the Geolocation API

Before we dive into the heart of the example let’s quickly look at the Geolocation API.

The elevator pitch is to the point- the W3C’s Geolocation API allows developers to retrieve the geographical location of a device. It became a Candidate Recommendation, the level at which the W3C deems features and functionality pretty much settled, in September of 2010 and already has support across a variety of devices and browsers. At the present time it’s supported all the major smartphone browsers and even on the desktop it’s supported by all major browsers except Internet Explorer 6, 7, 8 and Safari 3.2 and 4.0.

As a note, the Geolocation API was heavily influenced by the analogous functionality provided by the Google Gears plugin. This is why you often see the mothballed Google Gears plugin referenced as a fallback in many geolocation examples.

The API itself is straightforward. It provides a navigator.geolocation object which in turn provides two methods (watchPosition and getCurrentPosition) which allow the browser to query the device’s location through the use of location information servers. If you’re getting a location for use in a search or in a check-in, then getCurrentPosition is the method you want to use as it’s designed for a single location lookup. If you’re tracking a user’s location over time, then watchPosition is the way to go since it’s designed to be used over a longer period of time.

Location information is pulled from a variety of sources including IP address, device GPS, Wi-Fi and Bluetooth MAC address, RFID, or Wi-Fi connection location. The different level of precision inherent in these several methods is exposed by the API as an accuracy property.

Now that we’ve taken a look at the Geolocation API, let’s walk through our code in depth.

Getting Started with the Geolocation API

While the Geolocation API is straightforward, getting it up and running smoothly in the real world is a little bit tricky. Accounting for a successful result is one thing, making sure there’s a decent response for browsers without geolocation capability or in other instances where geolocation isn’t available is another.

Our example will touch on ways to minimize these issues and will illustrate the basics of a successful request.

Testing for the Geolocation object and Querying the User’s Location

The first thing you’ll need to do when working with Geolocation is to test whether or not it’s actually available in the browser. This is done by testing against the presence of the navigator.geolocation object. As you’ll see in the following code sample, this is a simple if…else block with a call to the navigator.getCurrentPosition() method when the object is present and a fallback when it’s not available.

The method getCurrentPosition() takes three arguments:

  1. the function to run on a successful location request
  2. the function to run as when the request fails
  3. a PositionOptions object containing other optional configuration objects.

In our case we’re passing in two named functions, success and failure, and an optional timeout of five seconds, which will keep things moving if something goes awry with the request.

Listing 1 Testing for the presence of the navigator.geolocation object

if (navigator.geolocation){  // does the geolocation object exist?             
  navigator.geolocation.getCurrentPosition( 
    success, 
    failure, 
    {timeout:5000} 
  );          
} else {
  failure();  
}      

In addition to the timeout seen in the previous example the PositionOptions object accepts two other options- enableHighAccuracy and maximumAge. enableHighAccuracy indicates that you would like receive the best possible results at the potential cost of speed or battery performance. maximumAge sets a limit, in milliseconds, for the age of a cached position object. The browser caches recent position location responses. Setting maximumAge to 0 will immediately force the browsers to try to obtain a new location.

Handling a successful geolocation request

The first function we’ll look at it is our success function. You can see it in Listin 1.2

In our example we’re using the Google Maps API to display a marker with the user’s current location.

The function accepts a single data argument. This argument is automatically passed into the function by the geolocation API. This is object is defined in the specification to contain two properties coords and timestamp. timestamp is, as expected, a timestamp indicating the age of the position information. For this example we’re most interested in the coords object which contains a latitude/longitude pair indicating the user’s position.

Moving on from the single argument, you’ll see several Google Maps specific variables.

The first, GM,represents a simple technique to speed up JavaScript. By creating a local representation of the google.maps object we save lookups to the global space. In general, local variables are faster. This is especially important with mobile which devices don’t have the fastest JavaScript engines.

Every little bit helps.

The most important piece, from a geolocation perspective, is the use of two properties, data.coords.latitude and data.coords.longitude, to build a new Google Maps LatLng object. The LatLng object is a core component of Google Maps. At its core it’s a latitude/longitude pair enhanced with methods and properties used throughout the API. To create one in our example you simply pass it the two properties of the data.coords object. We store that in our position variable.

We now have our user’s location, ready to place on the map.

The next section we’re using the Google Maps Geocoder to get a friendly label for the user’s location. Geocoding works in two ways. Normal geocoding means you pass the service an address string and it will return a series of geographical results. In our case we’re doing reverse geocoding, which means we pass the service a latitude/longitude pair and the service returns whatever it knows about the location.

Listing 2 Successfully handling a geolocation request

var success = function( data ){ //the data object, passed into success
  var GM = google.maps,
      mapOptions = {
        zoom: 12,
        center:  defaultPosition,
        mapTypeId:  GM.MapTypeId.ROADMAP
      },
      map = new GM.Map(  document.getElementById('map'), mapOptions),
      position = new GM.LatLng( 
        data.coords.latitude, //accessing the coords property
        data.coords.longitude 
      ),      
      niceAddress = "Your location",
      geocoder = new GM.Geocoder();
      geocoder.geocode( { 'latLng' : position  }, 
        function( results, status ) {
          if ( status == GM.GeocoderStatus.OK ) {
            if (results[0]) {
              niceAddress = results[0].formatted_address;
            }
          } 
          var infowindow = new GM.InfoWindow({
            map: map,
            position: position,
            content: niceAddress
          });
        });
      map.setCenter(position);
    }
  
  

Handling a Geolocation Failure

Our failure function handles two negative situations. If the user doesn’t have a geolocation enabled browser or if there’s an error in the geolocation lookup, this function is ready to step in and save the day. The failure function can be seen in Listing 3

You’ll see the setup is similar to the success function with a Google Maps object being created with some smart defaults.

The major difference is in the way we get the latitude and longitude for the map. Instead of getting the coordinates from a geolocation response we create a simple form to allow the user to enter their location. Inside the formResponse function we use then use the Google Maps Geocoding service to get a latitude and longitude pair corresponding to the location in the form submission.

Additionally we use the geolocation error response, if it exists, to build out a slightly more useful error message. If a browser supports geolocation and has some issue with the location request it should return an error response as the single argument to the provided callback function.

Listing 3 The failure Function

var failure = function( error ){ //The potential error response
  var  GM = google.maps,
       mapOptions = {
         zoom: 12,
         center:  defaultPosition,
         mapTypeId:  GM.MapTypeId.ROADMAP
       },
       map = new GM.Map(  document.getElementById('map'), mapOptions),
       formResponse = function(e){
         var geocoder = new GM.Geocoder(),
             position = defaultPosition,
             niceAddress =  "Sorry We Couldn't Find Your Location";
         geocoder.geocode(
           { 'address':  document.getElementById("location").value }, 
           function( results, status ) {
             if ( status ==  GM.GeocoderStatus.OK ) {
               if (results[0]) {
                 niceAddress =  results[0].formatted_address;
                 position = new GM.LatLng( 
                   results[0].geometry.location.lat(),
                   results[0].geometry.location.lng() 
                 )
               }
             } 
           var options = {
             map : map,
             position :  position,
             content :  niceAddress
            },
           infowindow = new  google.maps.InfoWindow(options);
           map.setCenter(options.position);
           document.getElementById("geocode").style.display="none";
         }
       )
     return false;
   }
   var  fallback = document.createElement("form");
   fallback.id="geocode";
   if ( error ) { 
     switch(error.code) {//Error Handling based on error.code   
      //HANDLE ERRORS//
   }      
 }  
 fallback.innerHTML  = "<label for='location'>Eneter Your Location" + 
  "<input  type='text' id='location' /></label><input type='submit'  />";
 fallback.onsubmit  = formResponse;
 document.getElementById("main").appendChild(  fallback );
};

The error response contains a code object indicating the type of error and a human readable message string that’s defined to be used in debugging or for error logs. There are four potential values for the error.code. These can be seen in Table 1:

Table 1 Possible error response codes

Code

Name

Definition

0

UNKNOWN_ERROR

The location lookup failed due to an undefined error

1

PERMISSION_DENIED

The location lookup failed because the application does not have permission to use the Geolocation API.

2

POSITION_UNAVAILABLE

The position of the device could not be determined.

3

TIMEOUT

The location lookup took longer than the length of time defined in

Putting it all together

Listing 4 shows the completed function. In it we’ve wrapped our two methods into a larger function called loadMap. Doing so allows us to streamline the code by creating a single set of defaults for the map and to encapsulate all of the functionality under a single function so as to keep the global namespace as neat as possible.

Listing 4 The Completed Function

var loadMap = function(){
  var GM = google.maps, 
      defaultPosition = new GM.LatLng(42, -71),
      mapOptions = {
      zoom: 12, 
      center: defaultPosition, 
      mapTypeId: GM.MapTypeId.ROADMAP},
    map = new GM.Map( 
      document.getElementById('map'), 
      mapOptions
    ), 
    success = function( data ){
      var position = new GM.LatLng( 
        data.coords.latitude, 
        data.coords.longitude 
      ), 
         niceAddress = 'Your location',
         geocoder = new GM.Geocoder();
      geocoder.geocode({ 
        'latLng': position },
         function( results, status ) {
           if ( status == GM.GeocoderStatus.OK ){
             if (results[0]) {
               niceAddress = results[0].formatted_address; 
             }
           }
           var infowindow = new GM.InfoWindow({
             map: map, 
             position: position, 
             content: niceAddress
           });
         }
       );
      map.setCenter( position );
    }, 
    failure = function( error ){ 
      var formResponse = function(){ 
        var geocoder = new GM.Geocoder(),
            position = defaultPosition, 
            niceAddress = 'Sorry We Couldn't Find Your Location';
        geocoder.geocode({
     'address':document.getElementById('location').value 
    }, 
          function( results, status ) {
            if ( status == GM.GeocoderStatus.OK ){ 
              if (results[0]) {
                niceAddress = results[0].formatted_address; 
                position = new GM.LatLng(
                  results[0].geometry.location.lat(),
                  results[0].geometry.location.lng() 
                )
               } 
             }
             var options = {
                map: map, 
                position: position, 
                content: niceAddress
              },
              infowindow = new google.maps.InfoWindow(options);
              map.setCenter(options.position);
              document.getElementById('geocode').style.display='none';
           }
         )
       return false; 
     } 
     var fallback = document.createElement('form');
     fallback.id='geocode';
      if ( error ) {
       switch(error.code) {
         case error.PERMISSION_DENIED:
     	    fallback.innerHTML += "<p>You chose not share geolocation data. Please, use the form below. </p>" ;  
         break;  
	 case error.POSITION_UNAVAILABLE:
            fallback.innerHTML += "<p>Sorry, we couldn't determine your location. Please, use the form below. </p>" ;
         break;  
         case error.TIMEOUT: 
            fallback.innerHTML += "<p>Sorry, the location request time out. Please, use the form below. </p>" ;
         break;  
         default: 
            fallback.innerHTML += "<p>Sorry, there was an error. Please use the form below. </p>" ;
         break;
       }  	
    }
    fallback.innerHTML += "<label for='location'>Eneter Your Location <input type='text' id='location' /></label><input type='submit' />";
    fallback.onsubmit = formResponse;
    document.getElementById("main").appendChild( fallback );
  };
  if (navigator.geolocation){
    navigator.geolocation.getCurrentPosition( success, failure, {timeout:5000} ) ;			
  } else {
    failure();	
  } 	
}

Summary

With that we’ve walked through the basics of the geolocation API. While our example utilizes the Google Maps API, any exploration of location based services can be based on the same pattern. Use the navigator.geolocation object where available, and then design in a simple fallback for non-supporting browsers and devices.

code used in the geolocation sample

My New Job

I’m late with this post. I’ve been busy! Finishing this post has been tougher than I imagined it would be.

Starting a new job is tough enough, adding in two visits to New York, one to Toronto and getting ready for HTML5 Live have made it even tougher. I think I’m through the toughest part of the transition now, so here I am, writing like a madman.

Anyway, I promised to talk a little bit about my new job. I won’t go into exhaustive detail, but I know some of you are interested, so I might as well get it out of the way now, before it doesn’t feel like a “new” job any more.

As I mentioned previously, I’ve moved over to Sapient Global Markets. My title is Senior Specialist, Platform.

As for what I’m doing, my job splits into three basic components- thought leadership, building a world class front end engineering team and bringing cutting edge solutions to clients.

  • Thought leadership. I’m not a huge fan of the phrase, but “writing and talking about emerging technology” doesn’t fit as well in a job description. I’ve already been doing this as much as possible. The difference with my new role is that it’s written into my job description and mandated from up on high. So, now I’ve got scheduled time for the kind of activities (writing, speaking, open source work) that I previously had to fit in around client engagements (which rarely happened) or after hours in my “free” time. Hopefully you guys will get some benefit out of me being able to write a little bit more.
  • Building a team. I’ve been instrumental in hiring and have worked developing junior staff for a few years now, so I’m pretty comfortable with this aspect of the job. The two key differences here are that I’m basically starting from scratch at my new role and I’ll be looking to build a truly global team. I’m not 100% sure what the eventually distribution will be, but I’ll be filling out slots between Boston, India and potentially a couple of other spots around the world. Making sure a team with that sort of geographical spread feel like a “team” will present a new wrinkle.

    Another clear challenge is cultivating front end engineering talent in India. Traditionally, people doing front end work there are junior and are doing so as a steppingstone on their way to writing “real” code- C# or Java. The combination of looking ahead to getting to do “real” work and the limited experience these guys possess have conspired to make it tougher than it should be to staff front end engineers in India. Hopefully I can help to change that by getting young Indian engineers excited about the web as a platform and open standards in general.

    By the way, one of those roles is already open. We’re looking for a Senior Interactive Developer in Boston. Come work with me. It’ll be fun. Shoot me an email, if you’re interested.

  • Client Work. The interesting challenge at this job is that I’ll be working with clients who are much more conservative than some of the organizations I’ve worked with previously. Educating some of the financial services giants on the power of the open web platform and delivering work that leverages those technologies in novel, but concrete ways will be an ongoing challenge. The good news is many of the cooler open web technologies are tailor-made for markets based businesses, so I’ll be selling them on Canvas, SVG, WebSockets, etc. Should be fun.

And that’s it. That’s the new gig. It’ll keep me busy for a while, I think.

My Slides from HTML5 Live

I’ve got three versions to share- a pptx, an old-school ppt and a pdf

I have no video. Video exists and I will share it as soon as I see it. I think it went pretty well, other than the fact that I surprised myself with the ending. I had adjusted some slides and forget where the last one was… all of a sudden it was over. Oops.

Still it went pretty well and I’m definitely going to do the same presentation at other venues. It’s a pretty good topic, I think, and I could tweak it to be super technical or more high level depending on the audience.

Thanks to the HTML5 Live folks for having me down to speak. It was a good time.