Twitter: raymondcamden


Address: Lafayette, LA, USA

Two iPhone development tips, and jQuery to the rescue

10-09-2008 27,744 views Development, jQuery 25 Comments

I've spent the last week or so doing iPhone web development. Let me be clear - that's web development. I'm not actually writing any fancy native applications for the iPhone. While most of my time was spent on just the basic work of the app (and I'll have some server side details on that tomorrow at ArgumentCollection), I wanted to look into what - if any - tweaks were available to on the iPhone web browser. I've found two things that I think are pretty interesting.

The first and simplest tip is working with the view port. (You may need to register at Apple in order to view that link. Two points off to Apple to requiring a login for simple docs!) The view port is a simple meta tag. Here is an example:

view plain print about
1<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">

This lets you configure the size of the content on screen when viewed on the iPhone. Read the docs as it takes a bit of play to get it just right, but it can make a major difference in how your web site looks on the iPhone.

The second tip also involves meta tags. While perusing the docs, I found a section on hiding the browser interface components. For web applications saved to the iPhone desktop, this lets you run a page without the normal address bar or status bar at the bottom. This is a great tip! It really does a good job of turning your web page into something closer to a native web app. This can be done with a grand total of two lines of code:

view plain print about
1<meta name="apple-mobile-web-app-capable" content="yes" />
2<meta name="apple-mobile-web-app-status-bar-style" content="black" />

In order to test this, you will need to open your page in Safari (on the iPhone), then add it to your desktop and reopen it. However this feature has a major flaw. As soon as you click a link it will 'break' out of your full screen web application and open a whole new Safari window. But get this - if you do a form post, it won't do this! So normal links are bad, form posts are fine. So when I first tested, and the app prompted me to login, I thought it was all fine, until I clicked a link after logging in. This isn't documented as far as I can tell, which kind of sucks. One Google search turned up a comment from a user who thought that maybe Apple was assuming only Ajax-based applications would use this feature - but if so - I don't get why form posts would work ok.

And this is where jQuery came in. The web application was already done (well, done enough) so it was too late to rewrite it to be Ajax based just for a minor (if cool) UI update. But then I remembered something. jQuery has a feature called selectors (Spry has this as well now!) that lets you select items from the document. You can select on various attributes, including simple all tags of a certain type. If I could select all the links, I could possibly add a click handler.

This is the test script I came up with:

view plain print about
1<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
2<meta name="format-detection" content="telephone=no">
3<meta name="apple-mobile-web-app-capable" content="yes" />
4<meta name="apple-mobile-web-app-status-bar-style" content="black" />
5
6<script src="/jquery/jquery.js"></script>
7<script>
8
9function test() {
10    $("#content").load('index3.cfm?log=<cfoutput>#randRange(1,100)#</cfoutput>');
11}
12
13function init() {
14    $("a").click(function(e) { $("#content").load(e.target.href);return false; });
15}
16
17$(document).ready(init);
18
19</script>
20<div id="content">
21<cfoutput>
22<p>
23<a href="index3.cfm?link=#urlEncodedFormat(createUUID())#">link to me, bad</a>
24</p>
25<p>
26    <a href="" onClick="document.location.href='test.cfm?link=#urlEncodedFormat(createUUID())#'">link to me, js</a>
27</p>
28
29<p>
30    <a href="test3.cfm?dontrun=1" onClick="test();return false;">link 3</a>
31</p>
32
33<p>
34    <a href="index.cfm">Naked Link</a>
35</p>
36</cfoutput>
37<cfdump var="#url#">
38    
39</div>

So what's going on here? The first link is a vanilla link. If I clicked on it, even though it was linking back to itself, it broke my full screen view. The second link used JavaScript and document.location.href. That also failed. I then tried Ajax. My third link used jQuery to load the contents of a file into a div I wrapped around my main content. Finally I tried one more simpe link, and then added jQuery code to find all the links and edit the click event:

view plain print about
1$("a").click(function(e) { $("#content").load(e.target.href);return false; });

This worked perfectly! In theory I just add this to my main template and all the links I have will now use AJAX to load their content.

I only have one issue left. Spry has a feature that works like the load() function in jQuery. But along with simply loading content, it can also filter to a particular div within the content. If jQuery can do that (I'm a bit tired now but I'm sure about 200 of my readers will chime in), then I can use this to load the page and not reload in the CSS/header/etc.

Related Blog Entries

25 Comments

These comments will soon be imported into Disqus. To add a comment, use Disqus above.
  • Commented on 10-10-2008 at 4:41 AM
    Ray,
    you should be able to get what you want with something like this:

    $("#mydiv").load("blah.cfm #TheDivIWant");
  • Commented on 10-10-2008 at 6:16 AM
    That worked perfectly Marc. I did this:

    $("a").click(function(e) { $("#content").load(e.target.href+' #content');return false; });

    Thank you.
  • Commented on 10-10-2008 at 6:22 AM
    surely!

    is this for the cfbloggers iphone page?
  • Commented on 10-10-2008 at 6:24 AM
    No, but I may use it. I find the view fine right now for CFB. But the full screen stuff may be nice. I also forgot to mention the tip on selecting an icon for your web app. Thats another meta tag. I'll blog that a bit laer.
  • Commented on 10-10-2008 at 6:49 AM
    New problem. The content loads fine - and just the div. But because I'm not rerunning the "mod my link" again, on the 2nd link it pops a new window. I need to mod my .load func to run the callback and update the links.
  • Commented on 10-10-2008 at 6:51 AM
    This seems to work just fine:

    function init() {
       $("a").click(function(e) { $("#content").load(e.target.href+' #content', init);return false; });
    }
  • Pollux #
    Commented on 11-25-2008 at 1:19 PM
    Hi, can you explain me how to do to have the apps always in full screen mode please. thanks.
  • Commented on 11-25-2008 at 1:22 PM
    Did you not see the meta tags above?
  • Rex #
    Commented on 12-14-2008 at 4:43 AM
    Sorry, just a little help. What I have to add exactly to my web page to make it works!! I downloaded jquery.js I put that in my main folder. I added the line in head part:
    <meta name="apple-mobile-web-app-capable" content="yes" />
    I linked the jquery plug in
    I put the script function (init).
    I tried all that in iphone, and the fullscreen works but when I try the link, Safari opens.
    Any little help? What I have to write exactly?
    Thank you very much!!
  • Commented on 12-14-2008 at 3:18 PM
    You may want to make sure the function is being run - you can add an alert() and see if the alert runs.
  • Commented on 02-01-2009 at 1:18 PM
    There's a much easier way I discovered:

    <a href="#" onClick="javascript:window.location.href='targetURL'">Click here to change page within webapp</a>

    Works just like a link but keeps you in the webapp.

    PS:
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    seems unneccessary
  • nono #
    Commented on 02-13-2009 at 5:48 PM
    This doesn't work for me:

    <a href="#" onClick="javascript:window.location.href='targetURL'">Click here to change page within webapp</a>

    work on first click but not on subsequent (launch Safari).
    However this did the trick:

    <a href="javascript:window.location.href='MyUrl.html'">Click me</a>
  • Commented on 03-03-2009 at 10:19 AM
    So just to be sure, function init() {
    $("a").click(function(e) { $("#content").load(e.target.href+' #content', init);return false; });
    } will load the content of the URL into the div with the id of content? If so, the same applies for any links which are within the returned content? Sorry if this sounds dumb but I have very little experience with AJAX and none with jQuery.
  • Commented on 03-03-2009 at 10:23 AM
    As far as I know, yes. Been a while since I looked at this code.
  • Commented on 03-03-2009 at 10:55 AM
    So would function init() {
    $("#content a").click(function(e) { $("#content").load(e.target.href+' #content', init);return false; });
    } apply it to only the A tags within the content div?
  • Commented on 03-03-2009 at 11:00 AM
    Yep.
  • Commented on 03-03-2009 at 2:45 PM
    Cool. Thanks man, you're a legend. :)
  • Commented on 03-03-2009 at 2:59 PM
    To be clear, this was something I tested. We did NOT end up using this in production. It has not been tested. Usage of this code does not apply any rights to your person. Using this code may cause drowsiness, spotting, and slight digestive pain. 4 out of 5 patients reported mild death after using this code. As with all code, be sure to consult with your doctor before making use of it. Thank you and have a nice day.
  • Commented on 03-04-2009 at 4:37 AM
    Ok. That was a bit random.
  • chris #
    Commented on 02-09-2010 at 6:07 PM
    Hi I realise it has been some time since there was a post here. I implemented your code and it works like a dream. I load content on the same domain/site, but I couldn't get this to work for a remote site. It struck me that this could be an "iframe like" substitute. Would it be possible to load a remote site with a bit of tweaking?
  • Commented on 02-09-2010 at 6:09 PM
    While iframe's may work, what you really want is JSON/P:

    http://www.insideria.com/2009/03/what-in-the-heck-...
  • Commented on 09-13-2010 at 3:26 PM
    Thanks for this solution. It did not meet my needs, but it got me on the right track. I had need to not just load new content, but also make sure any javascript on the page ran.

    What I did that worked, is on the click event,

    <ol>
    <li>I appended a new form to the body</li>
    <li>set the action to the link's href (less any query that was appended)</li>
    <li>parsed the query in the link (if present) and created fields as necessary in the new form</li>
    <li>and submitted the form</li>
    </ol>

    Not exactly elegant, but it works with a new page load for every click.
  • Don Alex #
    Commented on 01-12-2011 at 2:02 PM
    First sorry @ all but my english is bad, but I try my best!

    I got a website and im used this things:

    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <link rel="apple-touch-startup-image" href="http://***IMAGE_LINK.png***">

    and it works great. except one thing, if I'm click on a link, the link start loading but not in the "apple-mobile-web-app-capable"-mode but rather in the normals safari app.

    what can i do?

    thank you
  • Commented on 01-13-2011 at 11:11 AM
    You got me there. Are you saying you leave the current browser and open a new one?
  • Commented on 04-11-2013 at 1:10 PM
    Sounds like Don is having exactly the issue you describe and fix in this post. @Don, use AJAX or Ray's code above. You also have the fix in the mobile boilerplate https://github.com/h5bp/mobile-boilerplate/blob/ma... (see lines 24 to 34).