Using PhoneGap to Simulate a Derby app
330 ❘ CHAPTER 11 GETTING STARTED WITH PHONEGAP
} });
To make the call to an outside service for iPhone, you need to add the service to the external hosts in the PhoneGap.plist fi le. The easiest way to enable the external service for debugging is to add the * wildcard to the external hosts, as shown in Figure 11-26.
The data from the request string is placed on the responseText variable in the success callback. This can then be parsed with JavaScript’s eval function, which turns the XML into an array of items that can be used to get the items from the JSON response:
function successFunction(){ var dataItems = eval(“(“+this.responseText +”)”).d; for (var i = 0; i < dataItems.length; i++) { console.log(dataItems[i].Name); } }
LawnChair
LawnChair is a JavaScript library that was built to allow persistent storage of data in a lightweight application. The primary target for LawnChair is mobile HTML5 applications, due to LawnChair’s lightweight nature. To use LawnChair you need to set up a data store:
var store = new Lawnchair({name:’testing’}, function(store) {});
Once you have the store, you can create an object with a key, and then place that object in the store:
var me = {key:’adam’, lastName:’Ryder’}; store.save(me);
Now that the object is stored, you can retrieve it from the store using the key:
store.get(‘adam’, function(item) { alert(item.lastName); });
This would get the object and alert the lastName item from the object. LawnChair is small; only 8 K in size. This lends itself well to being packaged in PhoneGap, because it won’t take much space on the device.
BUILDING THE DERBY APP IN PHONEGAP
The idea of the Derby App is to build the same app over all of the mobile platforms covered in this book. The PhoneGap version is very similar to the other versions that you have built thus far or will build in future chapters.
FIGURE 11-26: External hosts with Item 0 Set to *
c11.indd 330c11.indd 330 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info
Building the Derby App in PhoneGap ❘ 331
The requirements are to provide two pages: one that lists all the teams/leagues and one that lists all the players. When a league/team is selected, the application shows the roster for the team. When a player is selected, it shows which team the player belongs to and her number.
The fi rst thing that you want to do in the Derby App is to create a placeholder which will hold the list of all the derby teams. You set this up on the index.html page:
<div id=”wrapper”> <div id=”scroller”> <ul> </ul> </div> </div>
You have set up the wrapper with an unordered list inside of the scroller. You need to add the listener for PhoneGap’s device ready event, and make a callback to the onDeviceReady function inside the onLoad function.
You also need to add a listener to the touchmove event to prevent the default touchmove behavior. Then you can use the iScroll library to control the movement of the screen:
function onLoad() {
document.addEventListener(‘touchmove’, function (e) { e.preventDefault(); }, false);
document.addEventListener(“deviceready”, onDeviceReady, false);
}
With the ondevice events wired up you can now request data from the derby name service. To accomplish this, create a fi le named OData.js to handle all requests to the oData Derby Names web service. This OData.js fi le will need to be included in your index.html header. The OData.js fi le has a getData function that takes a request string and a successFunction callback. The actual request is made using XUI’s XHR function, which calls the success function and passes the results from the request string to the function.
function OData() { this.getData = function (requestString, successFunction) { x$().xhr(requestString, { callback: successFunction, headers: [{name:”Accept”, value: “application/json”}], error: function(){alert(‘Error ‘); }}); };
Next, set up a DerbyService function that contains all of the service calls and builds the request strings and sends them to the OData function. The calls in the DerbyService contain functions to get the leagues and take a callback.
function DerbyService() {
this.HostName = ‘http://derbynames.gravityworksdesign.com’; this.BaseServiceUrl = this.HostName + ‘/DerbyNamesService.svc/’; this.odataService = new oData();
this.searchAllLeagues = function (successFunction) { var serviceString = this.BaseServiceUrl + “Leagues?$top=50”;
c11.indd 331c11.indd 331 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info
332 ❘ CHAPTER 11 GETTING STARTED WITH PHONEGAP
odataService = new oData(); odataService.getData(serviceString, successFunction); }; }
The onDeviceReady function calls setHeight, which is a function in your helper.js fi le and the searchAll function, which is a local function with a callback to an anonymous function that sets up the scrollView for your iScroll implementation:
setHeight(); searchAll( function(){ setTimeout(function () { scrollView = new iScroll(‘wrapper’, {desktopCompatibility:true}); }, 500); });
The searchAll function creates an instance of the DerbyService, and then calls the searchAllLeagues function of the derby service with an anonymous callback function. The anonymous callback will call another helper function to display the league data on the screen. The displayAllLeagueDataOnScreen function takes a parameter for the response from the OData service, the search string (currently empty string), and the ID of the div that will hold the results.
function searchAll(callback){ var service = new DerbyService(); service.searchAllLeagues(function(){ displayAllLeagueDataOnScreen(this.responseText, “”, “scroller”); } });
callback(); }
The displayAllLeagueDataOnScreen function uses jQuery to fi nd the list name, and removes any list items that are currently in the list. It then calls the appendAllLeagueDataOnScreen function, passing it the data, search term, and the list name:
function displayAllLeagueDataOnScreen(data, searchTerm, listName){ jQuery(“#” + listName).find(‘li’).remove(); appendAllLeagueDataOnScreen(data, searchTerm, listName); }
The appendAllLeagueDataOnScreen function calls the JavaScript eval function on the data to get an array of dataItems to work with. You also create a temporary singleItem to hold the league list item. You use jQuery again to fi nd the unordered list inside of the listName that was passed in. For every dataItem, you create a link that will go to the leagues page, league.html, which shows all of the players for that league.
After the item is created you append those items to the list. If the data item’s length is the same as the number of records you asked for, you also add a link to get more items when you scroll to the bottom of the list.
c11.indd 332c11.indd 332 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info
Building the Derby App in PhoneGap ❘ 333
function appendAllLeagueDataOnScreen(data, searchTerm, listName){
var dataItems = eval(“(“+ data +”)”).d;
var singleItem = “”;
var list = jQuery(“#” + listName).find(‘ul’);
for (var i = 0; i < dataItems.length; i++) {
singleItem = “<a href=’league.html?League=” + dataItems[i].LeagueName + “’>
<li title=”;
singleItem = singleItem + dataItems[i].LeagueName +” >”;
singleItem = singleItem + dataItems[i].LeagueName + “</li></a>”;
list.append(singleItem);
}
if(dataItems.length == 50){
if(searchTerm == “”){
singleItem = “<a href=’#’ id=’btnGetMore’ onclick=’LoadMorePushed()’>”
singleItem = singleItem + “<li id=’liAddMore’>Load More</li></a>”;
}
else{
singleItem = “<a href=’#’ id=’btnGetMore’
onclick=’LoadMoreSearchPushed("”;
singleItem = singleItem + searchTerm +
“")’><li id=’liAddMore’>Load More</li></a>”;
}
list.append(singleItem);
}
}
Figure 11-27 shows the index page rendering a list of roller derby teams.
Now that you have the leagues set up as a list of links to a league.html page, you can use CSS to change the links to look more like the native OS list items. You can set the list-style to none and the list-type to none, which will remove the bullets. When you set text-decorations to none for the anchor tabs, the links will no longer be underlined.
ul { list-style:none; padding:0; margin:0; width:100%; text-align:left; }
li { margin:5px 0; padding:3px 7px 7px 7px; border-bottom:1px solid #ddd; list-style-type:none; font-size:15px; font-weight:bold; margin-right:5px; }
FIGURE 11-27: List of derby
teams rendered on an
iPhone
c11.indd 333c11.indd 333 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info
334 ❘ CHAPTER 11 GETTING STARTED WITH PHONEGAP
a:link, a:visited { text-decoration:none; color:#000; font-weight:bold; }
Figure 11-28 shows what the Derby app looks like after this small amount of CSS has been added.
With the scrolling working and the list looking like a list, you can add a header to the league page. The header consists of two links with classes, which will become image links through CSS. This header will also be used on the individualList.html page, just with different classes, so that the links look different.
<div class=”header”> <a id=”btnLeague” href=’index.html’ class=”btnTwoLeft”>Leagues</a> <a id=”btnIndividuals” href=’individualList.html’ class=”btnTwoRightSelected” >Players</a> </div>
Here is the CSS for the buttons; the images are stored inside the images directory within the www directory:
.btnTwoLeft { height:23px; width:150px; background:url(images/btn-two-left.png) no-repeat; float:left; text-align:center; font-size:14px; font-weight:200!important; color:#fff!important; font:Georgia, “Times New Roman”, Times, serif; padding:7px 0 0 0; margin:2px 0; }
.btnTwoLeftSelected { height:23px; width:150px; background:url(images/btn-two-left-selected.png) no-repeat; float:left; text-align:center; font-size:14px; font-weight:200!important; color:#fff!important; font:Georgia, “Times New Roman”, Times, serif; padding:7px 0 0 0; margin:2px 0; }
With the header added, the league screen is now starting to look like a mobile app. Figure 11-29 shows the header added to the league screen.
FIGURE 11-28: Formatted
league list displayed on
an iPhone
FIGURE 11-29: Derby
App with header added
c11.indd 334c11.indd 334 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info
Other Useful PhoneGap Things ❘ 335
There is another useful option for a list this long, and that is the ability to search. To search, you need a text box for the search term, a button to search with, and another service call for searching:
<input id=”txtSearch” type=”search” placeholder=”Search” class=”searchbar”> <button id=”btnSubmit” type=”button” class=”gobtn” label=”Go” >GO</button>
Wire up the button click event in the onDeviceReady function. This click function gets the searchCriteria from the search text box and passes that to the searchLeagues function:
jQuery(“#btnSubmit”).click(function(){ var searchCriteria = jQuery(“#txtSearch”).val(); skipCount = 50; searchLeagues(searchCriteria); });
The searchLeagues function creates a new instance of the DerbyService and calls the searchLeagues function in the service with a callback to displayAllLeagueDataOnScreen. This is the same function that you called when you displayed the unfi ltered list.
function searchLeagues(searchCriteria){
var service = new DerbyService();
service.searchLeagues(searchCriteria, function(){
displayAllLeagueDataOnScreen(this.responseText, searchCriteria, “scroller”);
});
}
The searchLeagues function in the service calls the OData object with a fi lter that looks for a sub- string of the searchString that is passed in the LeagueName property:
this.searchLeagues = function (searchString, successFunction) { var serviceString = this.BaseServiceUrl + “Leagues?$top=50&$filter=\ substringof(‘” + searchString + “’,LeagueName)”;
this.odataService.getData(serviceString, successFunction); };
With the search in place, Figure 11-30 shows the completed UI for the Leagues screen in the Derby App.
With the Derby App completed, now you can take a look at some of the other useful functions in PhoneGap.
OTHER USEFUL PHONEGAP THINGS
Thus far, the examples in this chapter have provided the basics for creating a PhoneGap application. This application will go out to a web service and render the data on the screen. This does not cover every possible situation you will encounter as a PhoneGap mobile developer, so we will fi nish this
FIGURE 11-30: Derby
App with league
search added
c11.indd 335c11.indd 335 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info
336 ❘ CHAPTER 11 GETTING STARTED WITH PHONEGAP
chapter by providing a few short examples of other common tasks you may need to accomplish when working with PhoneGap.
Pickers
Pickers in PhoneGap come in two fl avors. The fi rst type of picker is a date-style picker. These pickers rely on plug-ins to function, because there isn’t a uniform date picker available to the different platforms yet. iOS 5 does support the HTML date input type. You can get the code for the date picker from https://github.com/phonegap/phonegap-plugins/tree/master/ iPhone/DatePicker. This will have the .js, .h, and .m fi les. The .h and .m fi les go into your Plugins directory. The DatePicker.js fi le belongs in your www directory. You also need to add a DatePicker key and value to the plugins section of your phonegap.plist fi le. You need to create a callback and a function that will be called during the onclick of a link.
var callbackFunction = function(date) {
console.log(date.toString());
document.getElementById(“date”).innerHTML = date.toString();
}
var showDatePicker = function(mode) {
plugins.datePicker.show({
date: new Date(),
mode: mode, //date or time or blank for both
allowOldDates: false
}, callbackFunction);
}
The other way to create a picker, which is our recommended way, is to create a page that lists the items you want to pick from as links back to your selector. In your HTML you could have a link to a pickList page:
<a href=’pickList.html’>Choose Your Favorite Color</a>
On the pickList page you can set up the list as a series of links back to the index with the choices differentiated by the query string parameter that is passed back:
<html> <ul> <li><a href=’index.html?color=blue’>Blue</a> <li><a href=’index.html?color=green’>Green</a> <li><a href=’index.html?color=red’>Red</a> </ul> </html>
Once back on the index page you can read the query string and take action based on what it con- tains. You can use regular expressions in JavaScript to decode the query string and return the value of the query string parameter. You could add another JavaScript library to handle this, but it is quicker and easier to just write the function yourself:
function getParameterByName( name ){ name = name.replace(/[\[]/,”\\\[“).replace(/[\]]/,”\\\]”);
c11.indd 336c11.indd 336 28/07/12 6:08 PM28/07/12 6:08 PM
www.it-ebooks.info