Back in November of last year I blogged an example of adding server-based login to a PhoneGap application. Essentially - how to create an HTML application on your mobile device that calls out to a remote server for authentication purposes. The blog post got quite a bit of traffic (and 100 comments at last count), but today a user pointed out an interesting issue and I thought it would be a great time to post an update to the demo with a fix in place. Basically, the user noticed something odd with login failures. The code I wrote supported caching the username and password values in LocalStorage and on application startup would automatically log you in. This worked fine - until your password was changed on the server. Consider the code below:
You can see that when an error is returned by the server, we use PhoneGap's Notification Alert API to let the user know about the problem.
Ok - so that should have worked, right? However - here is where we have a problem. Now - when I do blog entries and demos, I try to balance between 'real world' code and code that focuses narrowly on the issue I'm trying to discuss. I don't like a lot of clutter as I want people to learn without distractions. In this case though I built my demo using jQuery Mobile for the UI framework, and here's where the issue came about.
We listen for the pageinit event on the first page to fire off code that checks for cached login credentials:
This is a jQuery Mobile event. But PhoneGap has its own events - with the most critical of them being deviceready. You can't do anything device-related until this event fires.
So take a wild guess what happened. My jQuery Mobile page was up and running before my code was actually ready to speak to the device. (And if you are curious, I tested this using simple console messages. See my blog entry for more on that topic.) For my user, I just told them to quickly switch to a browser-native alert() call. But I really wanted a 'proper' fix.
This led to the question then: If I want my code to not do anything until deviceready is fired, what is the best way to handle it?
While I'm not sure this is the "best" way, here is the solution I came up with. I began by simply adding a new page to my initial HTML page. Remember that jQuery Mobile supports multiple "pages" per HTML file.
For the most part, this is the same as the previous blog entry. I did update to the latest PhoneGap and jQuery Mobile libraries. The critical part is the addition of "launcherPage." Now let's look at main.js:
The important changes are right at the bottom. I use the deviceready event callback (deviceReady) to register my pageinit function and also change the page manually from the blank screen to the 'real' login page. Now that the deviceready event has fired, when and if an error is returned by the automatic login, we can be assured that the native alert functionality provided by PhoneGap's API will actually work.
For those interested, I've included a zip of the code with this blog entry. You can upload it directly to PhoneGap Build to get a native installer on the platform of your choice.