Starting with verison 1.1.0RC1, jQuery Mobile changes the href
of any link to be #
when it is clicked, but only on iOS Mobile Safari. If you try to make a click handler that reads the href
attribute, you will be surprised to find that it does not get the href you intended. For example:
1 2 3 |
|
When using jQuery Mobile, this code will print out the href you expect on every browser except Mobile Safari on iOS (both real devices and simulators, but not with other browsers faking their User-Agent). On Mobile Safari, this will print out that the href is “#”.
The Problem
Obviously this is a problem if you have code that operates in a click handler that reads the clicked element’s href
attribute. jQuery Mobile changes that href before you get a chance to read it.
One common place this is used is with the link_to
helper in Ruby on Rails, for links that need to use other HTTP methods. For example, the standard RESTful way to delete a resource will be with a link that sets :method
to :delete
. Rails handles this with a library called jQuery UJS that needs to read the href from the link when it is clicked.
Unfortunately for Rails users, this means that Rails method links don’t work with jQuery Mobile on iOS Mobile Safari.
The Reason
The jQuery Mobile team is doing this on purpose, to make it so the address bar on iPhone does not drop down when changing pages (and we all love that feature!). In this discussion and this discussion, they seem to understand that this makes custom click handlers get the wrong href, but decide to go ahead with it anyway.
You can see it happen in this excerpt from the jQuery Mobile 1.1.0 source (reformatted for blog-friendlyness):
1 2 3 4 5 6 |
|
The Solution
Here’s the part that seems to be undocumented other than in that comment: they store the href in a data attribute! This makes this problem easy to workaround. Simply change your click handler to check for the data attribute first and fall back to the href:
1 2 3 |
|
That would be easy enough to encapsulate in a nice helper function…
Applying This To Rails jQuery UJS
If you use the Rails link_to
helper with the :method
option set to anything other than :get
, links are handled by the jquery_ujs
library that comes with Rails (often referred to as Rails UJS, jQuery UJS, rails.js). You’ll notice, for example that none of your :delete
links work with jQuery Mobile when you are on iOS Mobile Safari. You might see this as a missing route for your show
or edit
method depending on where you are linking from.
It turns out the fix is easy. The jquery_ujs code already has a method to encapsulate getting the href from an element, complete with a comment telling you how you can override it. All it does out of the box is read element.attr('href')
. All we have to do is override it and make it try the data attribute first.
Somewhere after jquery_ujs.js
is loaded, define this:
1 2 3 |
|
Now your Rails link_to
calls with custom :method
options such as :delete
will work just fine with jQuery Mobile 1.1.0 on iOS Mobile Safari, and you don’t have to lose that clever bit that keeps the address bar hidden.
UPDATED Jan. 3, 2013: I have confirmed that this problem has been solved in jQuery Mobile 1.2.0, and this work-around is no longer required. I did try to upgrade one of my jQuery Mobile 1.1.0 apps to 1.1.1 (but rolled back for other reasons), and in that process I believe that the above solution was still required.