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.

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.

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.

Using Lawnchair for Data Storage in PhoneGap

I’ve been looking around for good ways to store information for a PhoneGap application I’m working on. I think that the PhoneGap SQL APIs may still be the best bet but I also wanted to check out some of the more unique storage options. One of the options I came across was Lawnchair, by Brian Leroux. One of the beautiful things about Lawnchair is that it’s incredibly simple. It does persistent JSON storage, has adapters for different storage options (localstorage, webSQL, etc) and is very lightweight. One of the not-fun things about Lawnchair is that it’s incredibly simple. While I found it easy to use (mostly) there were some areas that didn’t work. I think part of the issue is that I don’t have a lot of experience with NoSQL solutions like CouchDB (where Lawnchair draws a lot of its inspiration) so I think a lot of the issue lies with me.

That said, I found it to be a powerful, if basic way to store data and I think it’s worth knowing about. This isn’t going to be helpful for people who know JavaScript pretty well or who have used Lawnchair a lot, but I figured jotting downs some of my thoughts and the basics of it would be helpful for my learning process. So here it is.

Quick Info Up Front

One of the first things I ran into was that Lawnchair will behave slightly differently depending on the adapter you end up using. For instance, I started out using the default ‘dom’ adapter, which just ties into the localStorage API and uses key/value pairs. So when you call the save() method, you pass in a key with values. But upon switching to the webkit-sqlite adapter, which relies on databases, I found that the old key/value pair code didn’t seem to work because of the way that the webkit-sqlite adapter assigns ids. The key is still stored, but it doesn’t seem to work as a selector. I think this might have something to do with the fact that I’m using ints as my key and not strings, but haven’t done enough research.

This post will use the webkit-sqlite adapter so keep that in mind as you’re looking at the code.

Getting Started

Getting started with Lawnchair is a beautiful thing. Simply drop the Lawnchair.js file and whatever adapter you want to use, then just start using the Lawnchair class. I found it’s helpful to assign it to a variable so that you can access it easily from other functions. It also requires a callback function. Normally, when you set the callback, you can use the this scope to perform operations on the database, but in my example I’m just tracing out that we connected.

     var beers = Lawnchair({name:'beers'},function(e){
          console.log('storage open');
     });

So beers is now the reference to my data storage and I can call the Lawnchair APIs using that variable.

Saving Data

While at first I was a little bit confused about how to treat Lawnchair as a way to store more complex data types, storing objects is incredibly easy. Just wrap whatever you want in a JavaScript object and then call the save method.

          var obj = {beername:"Wet Hop",brewername:"Deschuttes",brewerlocation:"Bend, OR"
                         ,beerstyle:"IPA",quantity:1,purchasedate:"12/11/2011",price:"9.00"
                         ,cellardate:"9/11/2011",cellartemp:40,brewdate:"8/10/2011"};
          beers.save({key:"1",value:obj});

In this case, I assigned a key of “1″, which makes sure it’s a string. If you just use integers, it ends up translating to the database as 1.0. This actually becomes kind of a pain later on as you’ll see, so it’s important to keep it in mind. If you use a string as your key, it will just make the ID that string, so it’s a little bit simpler to use. Below is what the data storage looks like when you don’t use a string.

By using strings I found it makes the retrieve operations a lot more simple. In fact, I couldn’t figure out how to use the get operation using the webkit-sqlite adapter and a number for the key. Getting 1 didn’t work and getting 1.0 didn’t work, so I just ended up using a string. I think that’s more a limitation of my JS knowledge than anything, but it was something that I struggled with.

One cool feature of modifying data in Lawnchair is that when you save() something, if you pass in a key that already exists, it will just overwrite that existing key. No having to worry about update versus insert, Lawnchair just figures it out and saves the data correctly.

Getting Data

There are a couple of good ways to get data; the first is the get() method. Pretty straightforward: You pass in a key, and it will return the value associated with that key.

             beers.get("1",function(obj){
                  console.log(obj);
             });

The object that comes back includes a key property and a value property, which is where the data is stored. So in my example object above, I can reference obj.value.beername to get the name of the beer.

Another helpful retrieve method is the all() method, which just dumps every object from the storage area in an array. Every function in Lawnchair can use a callback function and in this one it’s especially helpful. In my app I use the all() method to loop through the beers and display them in a 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 = arrBeers[i].value.beername;              
               $('#beer_list').append(listdiv);    
          }
          $('#beer_list').listview("refresh");
     });

Modifying Data

As I mentioned above, the way Lawnchair works is that when you save an object with the same key, it just overwrites it. So the key to modifying data is just grabbing it using the get() method, adjusting the data on the object, and calling save() with the same key.

          beers.get("1",function(thisobj){
               console.log(thisobj);
               var obj = {};
                    obj = thisobj.value;
                    obj.beername = "Not Wet Hop";
               beers.save({key:thisobj.key,value:obj});
          });

I found it kind of helpful to use the existing key on my retrieved object to save since that’s a good way to make sure you’re saving the object you want and not overwriting another one or creating a new one. Key management becomes kind of important with Lawnchair but it’s not tough to do.

Beyond

One of the things I found helpful after digging in was checking out the Lawnchair plugins. The couple that I downloaded were the query plugin and the callback plugin. The query plugin just lets you use some basic query syntax to pull out information. The callback plugin lets you specify callbacks for before and after events so you can make your code do specific things based on when you’re accessing the data.

It’s also really important to take a look at the adapters because that’s critical to making sure the application will work across devices. In general the adapters should be hot-swappable in that you should be able to just move adapters in and out without having to change the code. I had some trouble getting the latest DOM adapter to work, so I can’t totally verify that, but as I understand it that’s the way it’s supposed to work.

Conclusion

After messing with it, I think Lawnchair is one of the most straightforward ways to store data for a basic PhoneGap application. It’s not going to hold up to all of the use cases that a complex application needs, but for something where you’re storing some simple data, Lawnchair is perfect. It leverages existing web storage options and using adapters you can make sure it’s cross platform.

Full Code

I posted the full code snippet here. Keep in mind I’m a JavaScript newbie so if you see things I’m doing wrong I’d be grateful to hear about them.

Why I’m Doing PhoneGap

I’ve started to see some general questions and fielded a few emails from people asking about why the big push around PhoneGap on the Adobe side. In general, everyone knows the basic answer: we acquired Nitobi (the company behind PhoneGap), so now as Adobe evangelists, it makes a lot of sense for us to know it and be able to talk about it. And I think we’ve done a pretty good job of that. Christophe has a demo app (with source code) up, Greg has a couple of really good posts on it (especially this one that talks about how PhoneGap affects Flex evangelism). So at a general level, it shouldn’t be a huge surprise, but for me it’s quite a bit deeper than that and I wanted to provide a bit of context.

My desire to learn PhoneGap (and by extension get a lot better at HTML/JS) comes from two places. One, if you aren’t learning new technology, you’re not adapting as a developer. Two, as I’ve been looking around and trying to get my head around PhoneGap/HTML, I’ve found some rougher edges. Since I work at a tools company, I want to know where those edges are so that as Adobe builds out tools for this technology stack, I can provide good feedback to the product teams.

New Technology

I’ll say this a thousand times: I think AIR and Flex are the best way to build cross-platform mobile applications. I think they’re arguably the best way to build mobile apps in general for specific types of apps. And with AIR 3.0, AIR has never been more powerful. Stage3D is coming, we have native extensions and captive runtime so as a developer you can really blur the line between your AIR app and native functionality. But as great as I think native extensions are for our developer community, I’m not personally that excited by spending a lot of time writing them. I love the web. What got me so excited about RIAs back in the day was that you could build desktop-like apps with web technologies. I fully believe that Flash is part of the web, and I always will. Java and Objective C are decidedly not web technologies. And I’m not really that interested in spending a bunch of time learning Java/Objective C code. I don’t think that many AIR developers will have to roll their own native extensions, but it is one of the cool new parts of the platform, so a lot of the Adobe evangelists will be spending time getting up to speed on how to build them. That just doesn’t get me excited. Same goes for Stage3D. The stuff you can do with 3D in Flash Player is mind-blowing. I’m just not a 3D developer or a game developer. Luckily the Flash Platform is evolving beyond that as well. The stuff coming up with concurrency and potential enhancements to ActionScript both fall into what I’d call the “web world” and I’m excited to dive into those and get to know them as they get closer.

But, while I’m waiting, it turns out we now have a pretty cool HTML/JS mobile story with PhoneGap. I’ve been dabbling for a little while in jQuery mobile and HTML/JS and I’d consider myself an average JS developer. But you’ve always got to be learning, and if you love the web, you can’t not be good at JavaScript. I’m kind of ashamed that I’m not better, but this is a great opening for me to dive in, dedicate a ton of time and energy to getting better, and coming out a more holistic web developer. One of the things I love about the HTML/JS community is just how varied it is. There are JS developers of all stripes creating their own frameworks, own solutions to architecture problems, their own server solutions, and hell, even their own languages that eventually end up as JavaScript. The raw creativity of the web ecosystem is on full display when it comes to HTML/JS. And there is a certain zen to the chaos that I find intoxicating. I desperately want to be a part of that and the fact that I’m behind the curve is kind of depressing.

Helping Adobe

Which brings me to the second reason I’m planning to dedicate a ton of time to the PhoneGap stack. There are quite a few areas where the workflow is downright broken. My recent foray into on-device debugging is one example. Some of that is just that I don’t know enough, but there are also some real gaps in tooling, services, etc. We’ve got some smart people at Adobe who know the JS/HTML world pretty well. But we can always have more and if we want to provide value to developers in the space, that’s going to require knowing where the gaps are, knowing where to spend our time, and what kind of solutions will be helpful. I want to be able to provide that feedback and the best way to do that is to really know it. The hope is that I’ll be able to contribute in a small way to what Adobe will contribute to the open web ecosystem for developers.

Viva Flash!

So for me this particular foray goes beyond just learning PhoneGap to get up to speed. I think it’s a really cool time to be an Adobe evangelist and I came away from MAX a lot more invigorated than I’ve felt in a long time. Part of that is the Flash side (this session on the roadmap was excellent). But a big part of that was definitely that I think Adobe is going to make a positive impact in the HTML/JS space. The Nitobi guys are all insanely talented and I think that with them we’ve got a vision for mobile apps rooted in web technologies. I’m ready to contribute to that vision.

Update: And Ray pointed out he’s got a ton of stuff up as well.

PhoneGap for Flex Developers: Debugging PhoneGap Applications on Android

I’ve been spending a bit of time this weekend trying to dig into PhoneGap for obvious reasons. I’ve done a couple of basic PhoneGap apps prior to this but I wanted to get the full workflow down. Coming from a Flex/Flash background, I think I got a little spoiled. From what I’ve been able to tell, there’s almost nothing in the HTML/JS stack that can replicate what Flex/Flash Builder do. For this particular challenge I wanted to be able to debug my code on the device. Brian Leroux pointed me in some great directions but during the process I found myself a bit frustrated. There is a lot of “grab this github project, get this dependency, get this github project”, etc. That’s not to say it’s bad, it just wasn’t in a centralized place, which is what I’m used to. Simeon Bateman made an interesting comment to me over IM that I was from the “heavy, all-inclusive camp” whereas JavaScript developers came from the “lightweight, use-as-needed camp”. That’s something I need to get used to.

So here’s some general info I found while going through this process. Big disclaimer: This is more of a brain dump than anything, so it isn’t meant to be all that informative, but I wanted to jot it down for my own memory. Comments are welcome.

Aardwolf

The first thing I tried was Aardwolf, which seems really, really awesome. It’s essentially a remote debugger written in JavaScript. You open up the HTML page, which has a JavaScript console, and then load your application up on the device. It uses Node.js, which I thought was pretty slick, and by dropping a script into your page you can set breakpoints in the JavaScript console to test code. Sadly, I couldn’t get it to work. My main issue was that I had a hell of a time figuring out how to get the Node.js server exposed outside of my Mac correctly. I think I got close, but it stumped me. That’s not necessarily a knock on Aardwolf, because it looks really, really slick, I just didn’t have the Apache knowledge to pull it off. I’m going to revisit this one later.

Weinre

Weinre ended up being the winner for me. It seems like an absolutely perfect solution for the PhoneGap world because as long as you’ve exposed your Mac to web sharing, you can use the Mac client and with a simple line of code, you have access to everything about your application you’d expect from something like the Chrome Developer Tools. I think I’ll try to do a more in-depth blog post on this in the near future, but for now, here’s my rough setup:

I downloaded the Mac client from this page. I had web sharing on my Mac set up for the IP address 10.1.0.4. When it starts up, the Weinre client creates a ~/.weinre/ directory but if you want to customize the app at all you need to create a server.properties file in that directory. With this you can specify the host that the Weinre debugger will connect to. Mine was this:

boundHost:    10.1.0.4
httpPort:     8080
reuseAddr:    true
readTimeout:  1
deathTimeout: 5

Now the Weinre debugger is using the same IP address that any other devices use to connect to my Mac when they share the same network. When I read through the Weinre documentation, the examples focused on browser-apps that would be able to load a URL from that 10.1.0.4 URL. So at first I was kind of confused where PhoneGap fit in. But then I had my “duh” moment: one of the beautiful things with PhoneGap is that we’re just dealing with a web view instance in a native app. So all I had to do was take the script block that the “default” page creates for you and put that in my PhoneGap code. I started with the default PhoneGap template from Dreamweaver so I just added that line to my app:

<html>
<head>
<meta charset="UTF-8">
<title>Beer Inventory</title>
<link href="jquery-mobile/jquery.mobile-1.0a3.min.css" rel="stylesheet" type="text/css"/>
<script src="http://10.1.0.4:8080/target/target-script-min.js#anonymous"></script>
<script src="jquery-mobile/jquery-1.5.min.js" type="text/javascript"></script>
<script src="jquery-mobile/jquery.mobile-1.0a3.min.js" type="text/javascript"></script>
<!-- This reference to phonegap.js will allow for code hints as long as the current site has been configured as a mobile application.
      To configure the site as a mobile application, go to Site -> Mobile Applications -> Configure Application Framework... -->
<script src="/phonegap.js" type="text/javascript"></script>
<script src="scripts/test.js" type="text/javascript"></script>
</head>

It’s that first script block that gives me access to the Weinre debugger. Then I built that app and packaged it into an .apk file and installed it on my phone.

Voila! I automatically had access to all of the Weinre features for my PhoneGap app!

Fantastic!….err…..sort of

Being able to inspect elements and change them on the fly is awesome, but then I wanted to debug some JavaScript code. Turns out you can’t do that with Weinre (yet). This is one of the things that Aardwolf is really great at, but it has to tie into Node.js to get the breakpoints to work. Plus you have to manually enter an array of breakpoints in the JavaScript console to get it to work. I wasn’t able to get past the step of making Aardwolf and my local Node.js server accessible to my device, so I wasn’t able to test it. Plus I’m not totally sure how Aardwolf would work with PhoneGap, but I *think* it should. My plan this week is to try and get Aardwolf and my app running on Heroku so I don’t have to worry about making my local Node.js server accessible but I wasn’t able to do that tonight.

Welcome to the edge

As far as I can tell, we’re getting into some edgy territory here. Even the Google searches are pretty sparse. So if you’re coming from the Flash/Flex world, I think there will be some learning curves.

But I set out to do this with Android. For iOS, arguably the platform that is the most important, it’s way easy because the tools are much better. Since all PhoneGap projects are native projects, you can use the exact same debugging/deployment workflow as other iOS apps. That means you can leverage the power of Xcode to help out. I haven’t spent a ton of time in Xcode, so I’ll be spending some cycles on that this week as well, but it looks much, much nicer.

I’m really excited to spend a lot more time on PhoneGap. I think building apps with HTML/JS is kind of fun, even if there are some rough edges. Based on my experiments so far, the Flex/Flash story with AIR is way, way, WAY better than anything on the HTML/JS side for building mobile apps, including PhoneGap. But the world is embracing HTML and JavaScript and by learning JavaScript, as a developer, you will never be more versatile. So in that respect, PhoneGap is a great way to start bridging the gap between Flex/Flash and the HTML/JS ecosystem. So far I’m having fun.

Slides and Code from 360Flex Denver

360Flex Denver360|Flex Denver was an absolutely fantastic event. I was at the first 360 and have watched the event grow and mature over the years. It’s always been the best Flex conference out there, but there was something about those first few 360′s that had so much energy and got the community excited. This event felt like that. I’d rank it as one of the best 360′s I’ve ever been to. The attendees were enthusiastic and great to talk to, the keynotes were awesome and inspiring, and John and Nicole were at the top of their game as far as hosting went. It might have been all of the mobile stuff, it might have been the announcement on day 2 of Project Spoon, but this 360Flex was just all around great.

So of course, I made a bit of a misstep with my talk. At what was one of the greatest Flex conferences of the past 5 years, I go and give an HTML5/jQuery talk. But hopefully it was still fun. And to be honest, as I dove into HTML5 and jQuery for this talk, I learned that we have it very, very good as Flex developers. There are a lot of great things about HTML5 and especially jQuery, but if you’re building complex RIAs and applications, Flex has solved a ton of problems that the HTML5/JS world hasn’t yet. I definitely think they will, and the community around JS and jQuery is great, but as a Flex developer, you’ve got the best of both worlds and you’re going to be able to jump over to jQuery/HTML5 projects and bring some very valuable knowledge about building complex apps.

Thanks to everyone who attended the talk. My slides can be found here (and embedded below) and you can grab the demos from my GitHub repository here.

Building a jQuery Mobile Application with the PlayBook WebWorks SDK

I remain really impressed with the PlayBook as a device. It’s a great size, has fantastic specs, and the user experience that the QNX team has built is fun to use. Primarily I’ve been using the Flash-based AIR SDK for my tests and applications. I think that’s the best way to build PlayBook apps and when I’ve talked to people I’ve gushed that it’s the best mobile Flash development experience we have. But there are also a lot of JS/HTML developers who will want to deploy PlayBook content and RIM has included a WebWorks SDK to make that possible. So I took it for a spin, porting my landmark finder to the device.

Getting Started

The first thing you have to do is grab all of the required files. You first need to make sure you have the AIR 2.5 SDK (which, since we’ve moved to 2.6, can be found here). Then you can grab the WebWorks SDK and the simulator files from the BlackBerry developer site. By default the WebWorks SDK installs to your user directory, so if you can’t find it, look for a folder called bbwp.

Building the Application

There really isn’t any special trick to getting jQuery Mobile working on the PlayBook. It works perfectly and it performs really well. My application just took the core jQuery Mobile framework and included two different screens; one for getting the location and another for a list of landmarks that are close to you. It uses the GPS coordinates from the device and then goes out to Geonames to find a list of landmarks in the area. Selecting one of the landmarks takes you to Wikipedia so you can find out more about it.

The code (above) doesn’t have anything particularly tricky, which is a testament to how easy it use to use the WebWorks SDK if you’re an HTML/JS developer. I was even able to use the standard HTML5 Geolocation AP. RIM hasn’t announced any plans for geolocation on the device so I’m not sure what the final status or experience will be. Today on the simulator you can get a geolocation object but you can’t get position, so I just default to using the lat/lng from my neighborhood here in Seattle.

Creating the Config.xml File

The PlayBook uses a manifest file, config.xml, to control the title, icon, and features on the device. The config.xml file is pretty straightforward and if you’re familiar with app manifest files you should have no issues. There is also some decent documentation here. Mine is below.

There were a couple of gotchas I ran into when I dove into the config.xml file. The first was the access attribute. Instead of asking for blanket access to the web, you have to specify which domains your application will access. In my case it was just the Geonames API. But if you’re pulling down remote source files (say from jQuery) you’ll also need to include that domain.

Compiling the Application

Compiling and deploying the application was a bit tougher. Right now the only tools I could find are command line tools for the compiling, packaging, and deployment of WebWorks applications. The first thing you have to do is zip up all of the files you want to include in the application. The packager tool converts a .zip file into a .bar file, the native file format of the PlayBook. So I selected my config.xml file, my index.html file, and then all of the css and js files from jQuery to create geonames.zip. The tool you use to do that is in the bbwp directory in the root of the WebWorks SDK directory. Here’s the command. You can also specify an output directory with a -o switch. By default it creates a bin directory in the directory you’re in and puts the .bar file there (my WebWorks SDK is in an SDKs folder in my Library).

/Library/SDKs/com.blackberry.dev/bbwp/bbwp geonames.zip

That will build a geonames.bar file in the bin directory of your project.

Deploying to the Simulator

I won’t get into how to set up and configure the simulator because that’s been covered in other places. But once you have the simulator set up, you can test and deploy your application. Within the bbwp directory you’ll find a blackberry-tablet-sdk/tools directory, which has a bunch of libs for deploying and signing your application. To test it on the simulator you’ll use blackberry-deploy. To deploy it you have to have the simulator in development mode and know the IP address of the simulator and the password on the device. With that info you can deploy your .bar file to the simulator with this command.

blackberry-deploy -installApp -device  -package "bin/geonames.bar" -password  

And now you should be all set!.

Word of Caution

This particular example isn’t fantastic for the simulator because it uses the geolocation APIs, which aren’t supported currently on the simulator. But if you’re building a straight jQuery Mobile app (or any HTML/JS app) then these steps will get you compiled and on the device. The next step is to make sure your application is signed and then you can submit it to RIM’s App World and it’ll be ready to use when the PlayBook launches.

Presenting Node.js and Flash at FITC Amsterdam – Early Bird Ends Friday

FITC Amsterdam 2011If you’re on the fence for going to FITC Amsterdam you’re running out of time to lock in the early bird pricing. It ends on Friday, so register now!

I’m going to be presenting on Using Node.js and Flash together to create real-time, scalable applications using a combination of Flash and JavaScript. Node.js has been getting a lot of attention and so it should be a fun session. One of the coolest things this year about FITC is that there will be a ton of diversity in the talks. We’ve got everything from multi-screen, Flash, HTML5, 3D, gaming, so there really is something for everyone.

It’s going to be a monumental year for Flash developers with a lot of open questions and some great new technology to play with. FITC Amsterdam will give you some insight into how those technologies can be used and how to navigate the web application landscape.

Getting Started With jQuery Mobile

I’ve been spending a lot of time recently getting my JavaScript and HTML chops up because I think that Adobe is going to have a lot of impact in the HTML5/JS/CSS3 world next year and as a web developer, HTML and JavaScript have become incredibly interesting (and fun) with the rise of frameworks and the mobile landscape. As part of that experiment I’ve been digging into jQuery mobile. I’m obviously not a jQuery pro but after playing with both Flex “Hero” for mobile applications and now jQuery mobile, I thought it would be helpful to do a quick getting started post on jQuery mobile and talk about some of the UI paradigms it uses while walking through a basic application. jQuery mobile is in alpha2 right now, so it’s a little rough around the edges, but still very capable of providing a basis to create mobile applications.

jQuery Mobile divides the world up into pages, which are essentially just screens. Each page has three areas for content; the header, the main content, and the footer. Those are each defined by setting the data-role attribute within the div tag to specify “header”, “content”, or “footer”. The data-role attribute is also used to set up pages by setting it to the “page” value. With jQuery mobile the pages can be set up in different HTML files or all in one file. For this example I’m going to build a two-screen application. The first screen has a button that the user clicks to enable the use of the Geolocation APIs and the second screen is going to be a list of Wikipedia entries that are close to the coordinates. So I have two pages each with the three content types set using data-role.

 
<div>
 
<div>
 
<h1>Find Location</h1>
</div>
 
 
<div>
 
This application will use the <a href="http://geonames.org">Geonames</a> API and your location to bring back a list of Wikipedia articles about features that are near you. To get started, click the button below and allow the application to read your geolocation information.
 
        <input id="getLocation" type="button" value="Get My Location" /></div>
 
 
<div>
 
<h4>By <a href="http://blog.digitalbackcountry.com">Ryan Stewart</a></h4>
</div>
</div>
 
 
<div id="dashboard">
 
<div>
 
<h1>Data List</h1>
</div>
 
 
<div>
 
<ul id="wikiList">
</ul>
</div>
 
 
<div>
 
<h4>By <a href="http://blog.digitalbackcountry.com">Ryan Stewart</a></h4>
</div>
</div>

With my structure set up I can now start adding jQuery-mobile specific interactions. As soon as I add the jQuery mobile libraries to my application it knows how to parse the data-role attributes and themes the application accordingly. What you get is something like on the right. Notice how it automatically styles the header and footer sections as well as providing a nice, big, touchable button and some styling on the footer link to indicate that it can be tapped.

With the external jQuery and jQuery mobile files included I can move on to adding interactivity. I start by adding a click handler to my button, which will go out and grab the geolocation information if it’s available. It’s just using the HTML5 geolocation API, which is supported by most modern browsers. When the user clicks the button, it will get the current position and then call onSuccess or onError depending on whether or not the API call worked.

$(document).ready(function(){
     // Add a click listener on the button to get the location data
     $('#getLocation').click(function(){
          if (navigator.geolocation) {
               navigator.geolocation.getCurrentPosition(onSuccess, onError);
          } else {
               // If location is not supported on this platform, disable it
               $('#getLocation').value = "Geolocation not supported";
               $('#getLocation').unbind('click');
          }
     });
 
});

Next I set up a namespace for the geonames information. It has variables for the baseURL and then a search function with the getJSON function that goes out and calls the Geonames API. The function loops through each one of the results and then creates an <li> tag and appends the data we want to show to it, including the title of the Wikipedia article, the distance, and a summary. This is all straight jQuery. But after that we get into a couple of jQuery mobile-specific parts.

// create the geonames namespace for calling the API
var geonames = {};
     geonames.baseURL = "http://ws.geonames.org/";
     geonames.method = "findNearbyWikipediaJSON";
     geonames.search = function(lat,lng){
 
     // get the data in JSON format from Geonames
     $.getJSON(geonames.baseURL + geonames.method + '?formatted=true&amp;lat=' + lat + '&amp;lng=' + lng + '&amp;style=full&amp;radius=10&amp;maxRows=25',function(data){
          // Loop through each item in the result and add it to the DOM
          $.each(data.geonames, function() {
               $('
 
 
')
               .hide()
               .append('<a href="http://'+this.wikipediaUrl+'">
 
<h2>'+this.title+'</h2>
 
 
</a>
 
'+ this.summary + '
 
<span class="ui-li-aside">
 
<h5>'+this.distance+' (km)</h5>
 
 
</span>')
               .appendTo('#wikiList')
               .show();
          });
          // Once the data is added to the DOM, make the transition
          $.mobile.changePage('#dashboard',"slide",false,true);
 
          // refresh the list to make sure the theme applies properly
          $('#wikiList').listview('refresh');
     });
};

The page model in jQuery mobile gives you a lot of control over how those pages are displayed. By default, when you set up an anchor tag it will play a default transition and go to the page you want. If that page is an external page it will load that external page in the browser. If it’s an internal, local link (with a hash), then jQuery will perform a slide transition and then swap out the old page content with the new one. It also updates the URL by default so you can use the back button that’s included in the header or the back button on your device/browser and go back to the original page. Pretty slick that this all happens by default. However, if you want more control you can use the $.mobile.changePage method, which is what I’m using because I wanted to only change the page after I had parsed the data from Geonames. With mobile.changePage I specify the URL, which in this case is just the id of the new div tag, the transition I want, whether I want the animation to be reversed, and finally whether I want to change the URL so the user can go back to the first screen. By default when you use mobile.changePage the last attribute is set to false so it won’t update the URL in the navbar. In this case I want them to be able to update their location when they move so I set the property to true.

The last thing I have to do is refresh the list to make sure the styles are applied to the new data. Lists are incredibly sick in jQuery an jQuery mobile. By using the data-role attribute and the data-theme attribute you can create some very powerful lists. In this case, I’m just using the default list so my <ul> tag has an id of wikiList, and a data-role of “listview”. That means any <li> tags I add to it will become jQuery mobile list items. And that’s exactly what happens in my Geonames callback function when I iterate through each item. It’s creating <li> elements with my data and appending them to my wikiList <ul> tag. Then when I call .listview('refresh') on my wikiList, it styles them appropriately. One cool feature of jQuery mobile lists is that there are a few different properties I can set to add some stylistic touch. For example, to show distance I’m using a span tag with the class set to ui-li-aside. That class will right-justify the content so my distance shows up on the right side.

And that’s pretty much all there is to it. The last bit of code I have is just the onSuccess and onError functions that handle the geolocation API.

// Success function for Geolocation call
function onSuccess(position)
{
     geonames.search(position.coords.latitude,position.coords.longitude);
}
 
// Error function for Geolocation call
function onError(msg)
{
     alert(msg);
}

You can check out the full application here and see it in action. This is just scratching the surface of what you can do with jQuery mobile but hopefully you got a sense of the page model and how to move back and forth between screens. In some later posts I’ll hopefully cover the new gestures, the new components, and some of the ways to lay out content.