Defining Callbacks/Events Handlers for Mustache.JS Templates

This is pretty basic, but I had to do a bit of digging to figure out the answer so I wanted to post it. Essentially, since I’m using Mustache.js to load templates, I wanted to find a way to bind events to elements in those templates. My template has a form element and when the form gets submitted, I wanted to handle the data. The JavaScript is easy, especially with jQuery:

                         $('#beerform').submit(function(e){
                              var beer_obj = new Object();
                              $('#beerform :input').each(function(){
                                   beer_obj[this.name] = this.value;
                              });
                              beers.all(function(arrBeers){
 
                                   var beer_db_obj = {beername:beer_obj.beername,brewername:beer_obj.brewername,brewerlocation:beer_obj.brewerlocation
                         ,beerstyle:beer_obj.beerstyle,quantity:beer_obj.quantity,purchasedate:beer_obj.purchasedate,price:beer_obj.price
                         ,cellardate:beer_obj.cellardate,cellartemp:beer_obj.cellartemp,brewdate:beer_obj.brewdate};
                                   console.log(beer_db_obj);
                                   beers.save({key:arrBeers.length.toString(),value:beer_db_obj});
                              });

There’s kind of a lot of nastiness going on there, but basically I’m just getting all of the elements from the form that has been submitted, putting them into an object and then preparing them for the database and saving them using Lawnchair. The problem was that I was putting it in the same place I put all of my other JavaScript events, as a separate function inside my app.js file. But when I’d load the page and submit the form, nothing happened. It took me a couple of minutes to figure out what was going on.

Since Mustache doesn’t load things into the DOM right away, I had to make sure the above code was only being added after the Mustache template had loaded. By putting the code within the callback function for the original get() method, which retrieves the template with Ajax, and making sure the template had been injected into the DOM, it worked.

               $.get('templates/beer_add.mustache',
                    function(data){
                         template = data;
                         var renderedhtml = Mustache.to_html(template);
                         $('#content').html(renderedhtml);
                         // the template is now in the DOM
                         $('#beerform').submit(function(e){
                              var beer_obj = new Object();
                              $('#beerform :input').each(function(){
                                   beer_obj[this.name] = this.value;
                              });
                              beers.all(function(arrBeers){
 
                                   var beer_db_obj = {beername:beer_obj.beername,brewername:beer_obj.brewername,brewerlocation:beer_obj.brewerlocation
                         ,beerstyle:beer_obj.beerstyle,quantity:beer_obj.quantity,purchasedate:beer_obj.purchasedate,price:beer_obj.price
                         ,cellardate:beer_obj.cellardate,cellartemp:beer_obj.cellartemp,brewdate:beer_obj.brewdate};
                                   console.log(beer_db_obj);
                                   beers.save({key:arrBeers.length.toString(),value:beer_db_obj});
                              });
 
                              console.log(beer_obj);
                    });
 
               });

Fairly obvious once I figured it out, but I’m still having to remind myself of just how the DOM operates so I don’t run into issues like this.

2 Upcoming Presentations on HTML/JS/PhoneGap

I’ve got a couple of presentations coming up to Adobe user groups that are going to focus on HTML and PhoneGap.

The first one is in Las Vegas on December 7th. I’m doing an HTML5 Happy Hour and covering some of the cloud apps, what Adobe is up to with HTML, JavaScript, and of course Dreamweaver and PhoneGap. It should be a lot of fun. It’s at McMullen’s Irish Pub and starts at 6:30.

The second one is in January, at the newly rebranded Seattle Web App Developers Group. There I’ll be covering PhoneGap. This used to be the Flex Group so the presentation will take a bit of a Flex-centric slant, but I’m hoping to show Flex developers some of the fun parts of PhoneGap.

JavaScript Templating – Kind of Like ItemRenderers or Binding from Flex

One of the things I’ve been struggling with on the HTML/JS app I’ve been working on is how to get binding-like functionality. It seems like there are a few ways to do it, but the ones I looked at didn’t seem to fit with the general pattern of JavaScript and I wanted something a bit more elegant. Luckily, I just didn’t know what to look for, and once I came across templates, I realized I had found exactly what I wanted. Templates in JavaScript act like ItemRenderers but in my example I was able to use them to create a page, and then dynamically change the data on that page almost like I would if I were binding an object to a form in Flex.

And that’s almost exactly what templating lets you do. Here’s my example. I’m creating a list of beers, and when I click on one of those beers, I want to load a bunch of information about that beer in a form so I can make changes to it and save those changes to my database. With Flex Mobile I was able to do that pretty robustly because I can pass data between views very easily and bind elements in the second view to my data. With jQuery mobile, there’s nothing quite that fancy, so I had to rely on templates.

It turns out there are a ton of JavaScript templating libraries out there. Underscore.js includes a templating feature and looks interesting but I tried Mustache.js off the bat and found it pretty simple to use.

I started off with the template itself. In my case, it was a basic form that I called beer_detail.mustache

    <form action="#" method="post">
<div id="beername" data-role="fieldcontain">
            <span id="beerlabel">{{ beername }}</span>
            </div>
        <div id="brewername">{{ brewername }}</div>
        <div id="brewerlocation">{{ brewerlocation }}</div>
        <div id="beerstyle">{{ beerstyle }}</div>
<hr>
        <div id="quantity" data-role="fieldcontain">
<label for="quantityslider">Quantity: {{quantity}} </label>
<input type="range" name="quantityslider" id="quantityslider" value="{{ quantity }}" min="0" max="25"  />
</div>
        <div id="purchasedate" data-role="fieldcontain">
        <label for="purchasedatefield">Purchase Date:</label>
                <input type="date" name="purchasedatefield" id="purchasedatefield" value="{{ purchasedate }}"  />
</div>
        <div id="price" data-role="fieldcontain"><input type="text" value="{{ price }}"></div>
        <div id="cellardate" data-role="fieldcontain">
        <input type="date" name="cellarfield" id="cellardatefield" value="{{ cellardate }}"  />
</div>
        <div id="cellartemp">Cellar Temperature: {{ cellarTemperature }}</div>
        <div id="brewdate" data-role="fieldcontain">
        <input type="date" name="brewdatefield" id="brewdatefield" value="{{ brewdate }}"  />
        </div>
<a href="#pintley">This beer on Pintely</a>
        <button type="submit" data-theme="a">Submit</button>
        </form>

The double brackets {{ }} are all of the variable names that the template looks for so those will be replaced with actual data when the template gets rendered. I liked the similarity to Flex’s binding syntax.

One of the things you can do in jQuery Mobile is pass url variables, so for the first part of my application, I use a list of the beer names with a link to a page named beer_details.html that includes an id parameter that I use to look up the beer. In this example I’m using a Lawnchair database called “beers” and just calling the all() method to get all of the beers in the database. Then I iterate through those and build the list.

 
     beers.all(function(arrBeers){
          for(var i = 0; i<arrBeers.length;i++)
          {
               console.log(arrBeers.length);
               var listdiv = document.createElement('li');
                 listdiv.setAttribute('id','listdiv');
                 listdiv.innerHTML = '<a href="beer_details.html?id='+arrBeers[i].key+'">'+arrBeers[i].value.beername+'</a>';              
               $('#beer_list').append(listdiv);    
          }
          $('#beer_list').listview("refresh");
     });

The beer_details.html page itself just contains some skeleton code for jQuery mobile. The code will inject the template into the div id="content" tag. This way, all of the jQuery functionality stays with the application so it can use the back button, has the header/footer, etc and plays the transitions back and forth. So it’s pretty bare bones:

<div data-role="page" id="beerdetail" style="type-inline">
     <div data-role="header">
          <h1>Your Beers</h1>
     </div>
     <div id="content" data-role="content" align="center">
 
     </div>
     <div data-role="footer" data-id="foo1" data-position="fixed">
          <div data-role="navbar">
               <ul>
                    <li><a href="beers.html">Beers</a></li>
                    <li><a href="styles.html">Styles</a></li>
                    <li><a href="scan.html">Scan Barcode</a></li>
                    <li><a href="locations.html">Locations</a></li>                   
               </ul>
          </div>
     </div>
</div>

So now that the structure is set up, we can use Mustache to populate our template with data and inject the resulting HTML into the DOM. The first step is to set up the data object. In this code I parse the URL to figure out the ID of the beer, then use Lawnchair to retrieve that data. I’m listening for the pagebeforeshow method, but I’m not sure if that’s the best one. But it allowed me to get the data and change the DOM before the page showed, which is important for being able to render the template.

     $('#beerdetail').live('pagebeforeshow',function(e) {
          var beerID;
          beerData = {};
 
 
          var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');    
 
          for(var i = 0; i < hashes.length; i++)
          {
            hash = hashes[i].split('=');
            if(hash[0] == "id")
            {
                 beerID = hash[1];
            }
          }                 
 
     });

Once I have the beerID, I can use LawnChair to grab the information. Then I can use that object and pass it to Mustache to build the template. The Mustache library uses a .to_html() method that takes a reference to the template and the object that holds the data, in this case beerData. In the example below, there’s a bit of chaining going on. First I have to get the data, then when that is returned, it calls a function that will go out and load my .mustache template using Ajax, and finally, when that page is retrieved, I call Mustache.to_html() to get the HTML and then inject that HTML into the content so it will render correctly. This code goes inside the pagebeforeshow event handler.

          beers.get(beerID,function(obj){
               beerData = obj.value;
               $.get('templates/beer_detail.mustache',
                    function(data){
                         template = data;    
                         var renderedhtml = Mustache.to_html( template,beerData);
                         $("#content").html(renderedhtml);    
                    });
          });

And voila! Now when we click on a beer from the list, the data gets inserted into the template and when we move back and forth the data will update as we click on new beers.

This is much, much easier than trying to go through the DOM and insert/modify the form variables and also lets us potentially use different templates depending on the beer I choose. So far I’ve found templates to be helpful for getting around concepts like binding in HTML/JS.

I’ve gone ahead and put this project up on GitHub. It’s kind of a disaster at this point, since it’s basically my learning project, but you can see how this was done.

Beer and Cheese Pairings with A Dopple-Weizen, a Dubbel, and a Stout

I know this isn’t a tech post, but I’m working on getting back to blogging like no one’s reading. So bear with me and hopefully it adds a bit of personality.

I’ve been experimenting lately with cheese and beer pairings. I’m obviously a little bit biased, but I think the diversity of beer makes it a fantastic compliment to cheese. It’s not a new thing, but especially in America, which has taken the wine and cheese pairing route, it’s a bit of a niche. Which leaves lots of room for exploration which in turn leaves lots of room for exploration.

For this particular round I took 3 different beers and 3 different cheeses. The picture has 4 beers, but we didn’t get to the IPA. Kind of a bummer because IPAs make for some really interesting beer pairing, but alas, some beer has to be saved for later. Our beers were:

  • Lagunitas Dopple Weizen – A surprisingly crisp and tangy beer. They use yeast from Bavaria which I think gives the beer a really interesting flavor that mixes nicely with the crisp malt profile of the Dopple. Still retains a lot of the wheat character of the beer making it a mix of flavors that opened up a lot o cheese possibilities.

  • Full Sail Sanctuary 2011 – This beer deserves a year or two of conditioning in the bottle, but desperate times and all that. A great example of the dubbel style; bready, carmely malt goodness mixed with the banana, spicy belgian yeast. Slight hops to round out the beer, but basically a very drinkable Dubbel all around.
  • Alaskan Perseverance Ale – I can’t get enough of this beer. It’s a typical stout but brewed with birch syrup and fireweed honey. Both give the beer a very bitter sweetness which is a great compliment to the standard stout. It adds just a slight bit of extra to it that makes it stand out and makes it a very complex and fun to drink beer. It’s a 25th anniversary beer so grab some while you can.

Now, on to the cheeses:

  • Cypress Grove Chevre Truffle Tremor – Tangy, truffle goodness. Has a very sour, almost yeasty flavor to it. It’s an aged goat cheese, so the texture plays games with the beer a bit, but the truffle flavor makes it a unique pairing.
  • Willamette Valley Farmstead Gouda – I find Gouda to be a great beer pairing cheese. It’s got a creamy, nutty flavor that mixes really well with a lot of the more Belgian beers ends up bringing out some great flavors. This is an excellent (and Northwest local) Gouda to be the pairee.
  • Sartori Romano (grated) – Tangy, earthy, nutty with a nice finish. I find the italian hard cheeses kind of tough to do pairings with, but we had this for another part of the meal, so I gave it a shot. Not a major success, but no cheese is bad.

On to the pairings!

Lagunitas Bavarian Style Dopple-Weizen

The best pairing on the Lagunitas was with the Gouda. The earthy flavors of the Gouda really highlighted the estery parts of the Bavarian yeast in the Lagunitas. Taking a bite of the Gouda and a sip of the Lagunitas together was almost like an entirely new beer. The wheat and yeast flavors were enhanced and it really complimented the sour, tang of the beer. Probably my favorite pairing of the night. The Chevre didn’t really add a ton to this beer. Both were good but there wasn’t the interplay of flavors that I got with the Gouda. It was the same with the Romano. The two definitely worked together, especially the more nutty parts of the Romano, but it didnt’ quite dance in the same way as the Lagunitas and the Gouda did.

Full Sail Sanctuary 2011

The Full Sail and the Gouda actually weren’t as great a pairing as I was hoping. The flavors generally worked together, and some of the earthy notes of the Gouda played off the bready malts of the Full Sail but I was kind of disappointed with the overall result. The Truffle on the other hand, was much more interesting. The earthy, musky flavors of the truffle really did great things to the Full Sail. I think that the banana/spice notes in the Dubbel brought made a great contrast to the earthy, almost bitter parts of the Chevre. It’s kind of like the Truffle added some distinct bitterness that might usually come from hops in another style of beer, but in a way that was completely complimentary to the Full Sail. Great stuff. The Romano was a bit of a dud. Again, not a bad combination, just not one that had a ton of impact on the beer.

Alaskan Perserverance Ale

By far the hardest beer of the night to pair was the Perseverance. I find stouts hard enough to pair with cheeses, but with birch syrup and the just-off-center sweetness makes it even tougher. The Truffle stood up pretty well here. The truffell flavors didn’t exactly compliment the birch syrup sweetness, but it was kind of an interesting juxtaposition. The combination of that very tart aftertaste with the lingering bitter sweetness tickles the tongue a bit. Sadly, the Gouda didn’t stand much of a chance. It’s flavors just got overwhelmed by the beer. The salty/creamy parts of the Gouda were great, but in order to stand up to a big beer like a Stout, you have to have it in spades. Some Beecher’s Flagship might have been really interesting here. By this time we were out of Romano. It might have held up okay, but I have reservations. The Perseverance is a beer that stands on its own in a big way, so a cheese pairing is tough.

The winner was the Lagunitas and the Gouda. Just a really great mingling of flavors and a fantastic compliment. Second was actually the Truffle and the Perseverance. Maybe because I was three big beers in at that point, but the Truffle with it’s very tangy and creamy texture kind of held its own against the chocolate and bitterly sweet onslaught of the Perseverance. Surprising but tasty.

Congratulations MAX Masters

My second year being involved in the planning of MAX was even more rewarding than the first. And the average scores for all of ours speakers were up over last year so it seems like the content is resonating with attendees and we continue to draw great speakers. Thanks to everyone who spoke at MAX this year for making it a huge success.

But we also like to call out the best of the best. This year it was really tough to be a MAX Master and so a huge congrats to the following speakers who made the cut.

  • Adam Lehman, Adobe Systems
  • Bryan O’Neil Hughes, Adobe Systems
  • Chris Converse, Codify Design
  • Chris Kitchener, Adobe Systems
  • Colin Smith, Adobe Systems
  • Dani Beaumont, Adobe Systems
  • Dave Helmly, Adobe Systems
  • David Nuescheler, Adobe Systems
  • Duane Nickull, Adobe Systems
  • Greg Rewis, Adobe Systems
  • Jack Davis, Wow, Inc.
  • James Williamson, Lynda.com
  • Jason Levine, Adobe Systems
  • Jim Babbage, Adobe Systems
  • Joe Rinehart, Booz Allen Hamilton
  • Marc Esher, Booz Allen Hamilton
  • Michael Chaize, Adobe Systems
  • Michael Labriola, Digital Primates
  • Michael Ninness, Lynda.com
  • Mordy Golding, Design Responsibly
  • Nicholas Zakas, NCZ Consulting
  • Patti Sokol, Adobe Systems
  • Paul Trani, Adobe Systems
  • Russell Brown, Adobe Systems

Adobe Financial Analyst Meeting Being Live Streamed

Quick heads up that Adobe is going to webcast the financial analyst meeting on November 9th starting at 10:00 AM EST. The press release mentions:

At the meeting, which is being held in New York City, Adobe’s management team will outline the company’s vision and business strategy.

I haven’t been to one of these, so I’m not sure what you should expect (plus it lasts 7 hours) but it should be a good chance to see what Adobe is thinking.

Flex Mobile European Tour 2011

Next week I’m going to be hitting the road with my colleague Mihai Corlan to spread the news about what Adobe has been up to the past few months. The primary reason for the trip is to show off the work the product teams have done with Flex on devices. Mihai and I are going to be doing some hands-on sessions showing just how easy it is to build great looking applications for iOS and Android. Bring your laptop, a copy of Flash Builder, and a device and we’ll walk you through all the steps you need to go through to start building and deploying mobile applications.

The other part of these events is providing some firsthand demos of some of the things we showed off at MAX. I think MAX was a major turning point for Adobe and Mihai and I will be showing off the touch tooling, talking about the creative cloud, and showing all of the things Adobe is up to in the world of HTML5. Plus we’ll give you some sneak peaks of the next generation of the Flash Platform. So there’s a ton of info and you’ll have the chance to ask questions firsthand. 2012 is going to be a great ride for the Adobe community so we want to make sure you have all the info you need to be successful.

Here are the cities we’re hitting:

Update: For those of you in the UK, there is an event on Monday, the 7th. I couldn’t make it out in time for that, but Mihai will be there covering everything.

November 9th

November 10th

November 11th

November 14th

November 15th

November 17th

November 19th

Can’t wait to see you and talk about application development and Adobe’s 2012.