Must Read: JavaScript: The Good Parts

JavaScript: The Good Parts

JavaScript: The Good Parts

I just finished JavaScript: The Good Parts by Douglas Crockford and I highly, highly recommend it for anyone who is coming from a programming world that isn’t JavaScript. It’s an intelligent, and well-written book, but it also does the best job of anything I’ve seen yet at explaining some of the nuances of JavaScript and why they can be beneficial.

I was absolutely one of those people who looked at JavaScript as a runty kid brother when I compared it to ActionScript 3. I started off wanting a lot of what ActionScript 3 had in JavaScript. This book completely changed my opinion because it did a fantastic job of laying out how some of the seemingly less-well designed parts of JavaScript end up being pretty powerful. It also highlights some of the areas (like Scope) where JavaScript uses C-like syntax but doesn’t implement it in the same way and may trip up developers. Finally there are a couple of chapters on the bad and awful parts of JavaScript to be aware of.

In a lot of ways it’s the perfect book for someone coming from AS3 to JavaScript. I think it will give you some new found respect for JavaScript and help with some of the parts of JS that seem a little contrary.

Recreating the Path Menu with Adobe Edge

I saw this blog post by Victor Coulon about redoing the Path menu in CSS3 and thought it was really slick. I’m not as up to speed on CSS3 as I need to be yet, but after taking a look at the post, I thought this was a perfect use case for animation in an application. It’s unintrusive, adds some overall polish, and generally improves the user interface. I thought Victor’s demo was awesome and since this use case is a good one for animation, I thought it would be an ideal experiment for Adobe Edge. (Final result is here)

The Animation

Building the animation itself was quite simple. I took Victor’s graphics, made them transparent PNGs, and imported them into Edge. At that point it was just a matter of lining everything up and using the timeline to tweak the animation. I didn’t sit down and do the math on the circle, so the elements aren’t aligned perfectly (apologies) but it’s basically just six elements that all pop in from behind the plus button. With Edge it was pretty easy to add the bounce effect. I just set the easing property to easeOutBack and that gave me the bounce.

The project loaded in Adobe Edge

Interaction

While the animation was easy, it took me a bit to get the interaction down correctly. Basically whenever the red button was clicked I wanted to play the timeline animation. When it was clicked again I wanted to reverse it. Luckily Edge has a decent API that makes working with the code it generates pretty straightforward. The biggest issue I ran into was that the playReverse() API can only be run on a symbol and I was having trouble figuring out how to get a symbol instance from within my click event. Running play() on the Composition (kind of the main Edge element, and the one Edge uses by default) runs off an entire set of other operations that made it tougher to do what I wanted.

So instead I used comp.getStage() to get an instance of the “stage” symbol where I could play and reverse the timeline at will. The result is pretty close to what Victor created and what the Path app uses. To do it all, I replaced the Adobe Edge DOM Ready Event Handler code in my project_name_edge.js file with the following:

/**
 * Adobe Edge DOM Ready Event Handler
 */
$(window).ready(function() {
     comp = new Edge.Composition(compId, {stage: "." + compId}, {});
        /**
 * Adobe Edge Timeline Launch
 */
     comp.ready(function() {
         var symb = comp.getStage();
 
         $('#stage_add_button').click(function(e){
               if(played)
               {
                    symb.playReverse();
                    played = false;
               } else {
                    symb.play();
                    played = true;
               }
 
         });
     });
});

Downsides

One downside is that once I make a change in Edge it overwrites all of the changes I’ve made. I’m not sure if there’s a safe place to make JavaScript edits like the one above but I’m going to check with the team. The other downside is that it’s all JavaScript, which makes it kind of heavy and you won’t get the hardware transforms that some browsers use for CSS3. I’m not much of a designer but after this little proof of concept I’m excited to see how Edge could potentially be used to add some fine-tuned interactions like the Path menu.

You can see a working demo here and the source for the project is up on GitHub.

Passing Data Between Pages in jQuery Mobile

Coming from Flex one of the things I’ve struggled a bit with is passing data between views in my jQuery Mobile applications. The template approach with Mustache worked really well, but it also had a lot of overhead. In fiddling around today I found a more hacky way that seems to work pretty well (though I think the Mustache route is still better). It relies on the fact that the pagebeforeshow method provides a prevPage property as part of its data object. That prevPage property is just a representation of everything in DOM of the previous page. That means it’s relatively easy to use selectors and that object to pass data to the new page.

The setup of my pages is as follows. My first page has a list of breweries, and each brewery page has a list of the beers that brewery uses. When you click on any of the beers, it goes to a form that can be used to rate the beers and provide some extra information about them. My goal was to prepopulate some of those forms with the beer data I already had. For instance I know the beer name, brewery, and style of each beer, so I should be able to prepopulate those, but they change for every beer so it has to be dynamic.

Within each page I defined a hidden div with two span elements with ids that represent the brewery name and brewery location (since they’re the same for every beer). Then within the beer list I have a hidden div that contains the beer name and the beer style. Here’s an example:

<div data-role="page" id="aleasylum" data-theme="e" data-add-back-btn="true">
     <div data-role="header">
          <h1>Ale Asylum</h1>
     </div>
     <div style="display:none">
          <span id="brewernameinfo">Ale Asylum</span>
          <span id="brewerlocationinfo">Madison, WI</span>
     </div>    
     <div data-role="content">    
          <ul data-role="listview">
               <li data-role="list-divider">Year Round Beers</li>
               <li>
                    <a href="#beerdetails">
                         <img src="images/hopalicious-thumb.gif" />
                         <h3>Hopalicious</h3>
                         <p>5.8% abv. Eleven separate additions of cascade hops give this American pale ale its lush citrus aroma and bold hop flavor without crazy bitterness. Hopalicious is available year round in six packs and on tap throughout the Madison and Milwaukee regions.</p>
                         <div style="display:none">
                              <span id="beernameinfo">Hopalicious</span>
                              <span id="beerstyleinfo">IPA</span>
                         </div>
                    </a>
               </li>
               <li>
                    <a href="#beerdetails">
                         <img src="images/madtown-nutbrown-thumb.gif" />
                         <h3>Madtown Nutbrown</h3>
                         <p>5.5% abv. Our nutbrown ale is velvety smooth with a rich caramel aroma. We blend seven different malts for just the right touch of sweetness and a creamy finish youÔøΩll really dig. Madtown Nutbrown is available year round in six packs and on tap throughout the Madison and Milwaukee regions.</p>
                         <div id="info" style="display:none">
                              <span id="beernameinfo">Madtown Nutbrown</span>
                              <span id="beerstyle">IPA</span>
                         </div>                        
                    </a>
               </li>

So in order to grab that, I just added an event listener to the pagebeforeshow method that uses selectors to grab the data. One of the critical parts is that jQuery selectors have an optional context property that can be set so that jQuery only selects from that context. In this case, since my pages are all using the same id names for the values, I need to set the context so that the selectors are only pulling from the previous page and not the entire document.

 $('#beerdetails').on('pagebeforeshow',function(e,data){
     var beername = $('.ui-btn-hover-e #beernameinfo',data.prevPage).text();
     var brewername = $('#brewernameinfo',data.prevPage).text();
     var brewerlocation = $('#brewerlocationinfo',data.prevPage).text();
     var beerstyle = $('.ui-btn-hover-e #beerstyleinfo',data.prevPage).text();
     $('#beername').val(beername);
     $('#brewername').val(brewername);
     $('#brewerlocation').val(brewerlocation);
     $('#beerstyle').val(beerstyle);
 });

The code above executes before anything gets displayed on the new page, grabs the values from the first page with the hidden div tags, and then sets some of the form fields to those new values.

It strikes me as a bit odd that there isn’t an easier way to do this, so it could be that I’m just not googling the correct thing and jQuery Mobile has something built-in to help with this issue. It does seem like this can be done by using URL variables, but what I like about this approach is that it’s a bit more semantic and there’s no required parsing of the URL string.