Tweet |
HTML5 has the "write once, run anywhere" capability that first attracted me to
Java back in JDK 1.0 days. The downside to this it that it does reduce the
functionality available. For example, offline storage is problematic at
the moment with different browsers supporting different standards, and the
standards themselves being subject to change, while access to native
functionality is still in very early days (Android makes the camera available
through javascript but there aren't many other examples out there). It
very much feels like the future though, so I've been heading down that route.
My first foray into developing a mobile front end was for our BGFM product for
Dreamforce 2010. This was simply some Visualforce pages sized and styled
appropriately for the iPhone. The obvious downside to that was that a
device with any other form factor needed separate pages (or at least pages
that could adjust themselves appropriately). However, towards the middle
of 2011 I came across JQuery Mobile (JQM) and starting using the 1.0 alpha
releases. The great thing about JQM is that it takes care of the cross
device side of things, leaving you with one app that works across all popular
smartphones, tablets etc. Even better, it will also work against older
devices, dropping back down to basic HTML if necessary. For details,
documentation, tutorials and samples, check out the JQuery Mobile site.
Building Visualforce pages that leverage JQM is pretty straightforward.
Lifting from the getting started page from the JQM site:
<apex:page showHeader="false" sidebar="false" standardStyleSheets="false"> <html> <head> <title>My Page</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>My Title</h1> </div><!-- /header --> <div data-role="content"> <ul data-role="listview" data-inset="true" data-filter="true"> <li><a href="#">Acura</a></li> <li><a href="#">Audi</a></li> <li><a href="#">BMW</a></li> <li><a href="#">Cadillac</a></li> <li><a href="#">Ferrari</a></li> </ul> </div><!-- /content --> </div><!-- /page --> </body> </html> </apex:page>
As you can see from the code, I've had to do nothing to style this
appropriately for the device, simply giving the unordered list a data-role of
listview means that JQM takes care of all the heavy lifting. Adding buttons
for simple navigation is also straightforward, and JQM provides some
transitions to mimic native apps. Again, its all taken care of by the markup:
resulting in a couple of appropriately styled buttons at the bottom of the page:
Where things get a little more interesting is if you have a form in the page and the buttons are submitting the form rather than simply moving to a new page, as is the case in most of the Visualforce pages I write.
In that case I'd like to use an <apex:commandLink> component, but I can't provide the additional attributes to lay things out correctly - e.g. data-inline="true". While I could write some Javascript to take care of this, in the first instance I'm trying to keep things simple, so I use an <apex:actionFunction> component and tie this to the JQM specific link via an onlick handler as follows:
Standard <apex:inputField/> components also render well most of the time - sometimes I end up using the input text/textarea/checkbox etc to allow for a greater level of control, but a basic form can be created with the minimum of effort. For example, a simple form to create an account by specifying its name and industry only requires the following markup:
Produces the page shown below - not too bad for a few lines of markup:
Obviously once the record is saved, the user is redirected to the standard view page which looks pretty awful on a phone, so standard controllers probably aren't going to be a silver bullet for this, making it the usual challenge for editions below enterprise.
I've put together a demo application that allows a contact to take a survey. Its hosted on an unauthenticated Force.com site so is publicly available. A couple of sample screen shots are shown below:
If you'd like to try out the demo application, simply click here.
A couple of points to note:
Follow @bob_buzzard
<a href="index.html" data-role="button" data-inline="true">Cancel</a> <a href="index.html" data-role="button" data-inline="true" data-theme="b">Save</a>
resulting in a couple of appropriately styled buttons at the bottom of the page:
Where things get a little more interesting is if you have a form in the page and the buttons are submitting the form rather than simply moving to a new page, as is the case in most of the Visualforce pages I write.
In that case I'd like to use an <apex:commandLink> component, but I can't provide the additional attributes to lay things out correctly - e.g. data-inline="true". While I could write some Javascript to take care of this, in the first instance I'm trying to keep things simple, so I use an <apex:actionFunction> component and tie this to the JQM specific link via an onlick handler as follows:
<apex:form id="jsfrm"> <apex:actionFunction action="{!save}" name="save"/> ..... <a href="#" data-role="button" data-inline="true" onclick="$.mobile.showPageLoadingMsg(); save()">Save</a> ..... </apex:form>The $.mobile.showPageLoadingMsg(); function call simply displays a spinner to let the user know something is happening.
Standard <apex:inputField/> components also render well most of the time - sometimes I end up using the input text/textarea/checkbox etc to allow for a greater level of control, but a basic form can be created with the minimum of effort. For example, a simple form to create an account by specifying its name and industry only requires the following markup:
<apex:page showHeader="false" sidebar="false" standardStyleSheets="false" standardController="Account"> <html> <head> <title>Create Account</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Create Account</h1> </div><!-- /header --> <div data-role="content"> <apex:form id="jsfrm"> <apex:actionFunction action="{!save}" name="save"/> <apex:outputLabel for="name" value="Name"/> <apex:inputField id="name" value="{!Account.Name}"/> <apex:outputLabel for="industry" value="Industry"/> <apex:inputField id="industry" value="{!Account.Industry}"/> <a href="index.html" data-role="button" data-inline="true">Cancel</a> <a href="index.html" data-role="button" data-inline="true" data-theme="b" onclick="$.mobile.showPageLoadingMsg(); save();">Save</a><br /> </apex:form> </div><!-- /content --> </div><!-- /page --> </body> </html> </apex:page>
Produces the page shown below - not too bad for a few lines of markup:
Obviously once the record is saved, the user is redirected to the standard view page which looks pretty awful on a phone, so standard controllers probably aren't going to be a silver bullet for this, making it the usual challenge for editions below enterprise.
I've put together a demo application that allows a contact to take a survey. Its hosted on an unauthenticated Force.com site so is publicly available. A couple of sample screen shots are shown below:
If you'd like to try out the demo application, simply click here.
A couple of points to note:
- I've put this together over a few weekends so I wouldn't be in the least bit surprised if there were some glitches waiting.
- I've only tested it with an iPhone and webkit browser, though I can't see why there would be issues with different devices.
- This is a real functioning application, so the feedback will be stored in my Salesforce instance - so if you feel like leaving real feedback, I may even act on it!
Follow @bob_buzzard