Wednesday, November 30, 2011

jQTouch Dynamic Links and Event Handlers

Alright, so one of the biggest worries I had while developing the jQTouch UI for my recent app (the first app I've ever developed with jQTouch) was generating dynamic links and getting event handlers for dynamic links.

Here's the basic idea, I had a list of items that was returned from a AJAX call, and I wanted to generate a link for each of the items.

So easy enough:

jQuery.each(data, function(){
ihtml += "<li><a href='#'>" + data.item.name + "</a></li>"
}

So that generated the links which was all good. But then I came across the problem of how do I react to each link - or at least how do I handle a click of the link and figure out which link was clicked.

The way I did this was by giving the same "id" attribute to all of the links, but then I added a custom attribute called "item_id". So my link generation became:

jQuery.each(data, function(){
ihtml += ihtml += "<li><a href='#' id='itemlink' item_id='" + data.item.id + "'>" + data.item.name + "</a></li>"
}

So each link woud have the same "id", but they would have a different "item_id".

Then using the jQTouch call back events, I extracted that "item_id" when the link was clicked.

$("#itemlink").tap(function(e, info) {
loadItem($(e.target).attr("item_id"));
}

The $(e.target) essentially grabs the element that was tapped. Then you can call your standard element inspection methods on it like .attr("item_id").
And my loadItem function would be something like

function loadItem(item_id) {
/*make AJAX call using item_id */
}

So each link will react to this, but then the attr("item_id") will be different.

Hope that makes sense.

Heroku, jQTouch, iPhone Fullscreen Image Refresh Issues

Alright so today things were going pretty well with development on my open mic community app so I decided to work on some of the graphics. After spending some time deciding on what I wanted to change, I came up with some graphics I was happy with.

App Background: Ruby on Rails 3 app, hosted on Heroku with JQTouch for iPhone UI.

So I updated my local git repository, pushed it to github, and then to heroku. Since I've been testing my app a lot, I already had it added to my homescreen. So I hit the Homescreen icon which launched my fullscreen webapp - but my new images weren't showing up.

So to debug, I decided to launch safari and navigate to my page - the new images were showing up there. That's weird - because it was my understanding that the fullscreen iOS webapp was just Mobile Safari without the address bar and controls at the bottom.

So it's really weird that it was rendering the new images in Mobile Safari but not from my shortcut. So I decided to delete my homescreen shortcut. I navigated to my page (in Mobile Safari where the new images showed up) - and added a shortcut to my homescreen.

I tapped the homescreen icon - and still nothing! The old images were still coming up. I cleared my cache and HTML data - and still nothing.

I was getting quite frustrated and decided to leave it alone and figure it out later.

I came back to my app a few hours later - and boom - the new images had loaded!

So turns out it was just a matter of time. I have no idea what's being cached and where. Didn't seem to be an issue with Heroku nor with Rails since Mobile Safari was rendering it properly. It seems to be iOS's fullscreen app runner that was doing some caching somewhere.

So long story short - if this happens to you - just wait a while - the refresh should happen.

Tuesday, November 29, 2011

jQTouch, AJAX, Ruby on Rails

Alright, this is the beginning of my blog entries concerning software development as I get more and more passionate about it.
Today, I findings on jQTouch, AJAX, and Ruby on Rails.
jQTouch is a nice little javascript library that makes is super simple to develop webapps that look great on the iPhone. So much so that if a user adds your homepage to their homescreen, it looks so much like a native app it hurts! (well, it doesn't really, but it's quite nice).
There are other alternatives out there like iUI, jQuery Mobile and Sencha, but I decided that jQTouch was a good in-between of everything.
So the big problem I had today was that I was having a lot of issues getting the my webapp on the iPhone to make an AJAX call. When I ran the app in Chrome on several computers, there was no problem.
Quick App Summary: App built in Ruby on Rails 3, using jQTouch for the iPhone UI, and jQuery to make the AJAX calls.
I narrowed it down to it being a 406 error. Using the following code:

$.ajax({
url: '/sessions/test',
dataType: 'json',
success: function(data, textStatus, jqXHR){
alert(textStatus + ': ' + jqXHR.responseText);
},
error: function(jqXHR, textStatus, errorThrown){
alert(textStatus + ":" + errorThrown + ":" + jqXHR.status);
}
});

After that I realized my 406 error was actually stemming from how I interpreted iPhone requests.
In my Application controller, I had a bit of code that would basically look at the User Agent to determine whether or not I would use the regular Web Interface, or the Web Interface designed for the iPhone. To do this, I had a few methods like this:

def set_ios_format
if is_iphone_request? or request.format.to_sym == :iphone
request.format = if cookies["browser"] == "desktop"
then :html
else :iphone
end

# Handle AJAX Requests
if request.xhr?
request.format = :json
end
end
if is_ipad_request? or request.format.to_sym == :ipad
request.format = if cookies["browser"] == "desktop"
then :html
else :ipad
end
# Handle AJAX Requests
if request.xhr?
request.format = :json
end
end
end

You see that bit of code in there that says "Handle AJAX Requests" - this is what was missing. The problem is, when the iPhone was making an AJAX request, my Ruby on Rails code was treating that like a iPhone browser request - and setting the format to "iphone" which is an illegal format for the iPhone to accept via AJAX request.
So I do a quick check to see if the request is coming from a xhr, and if it is, set the format to "json" - could have set it to xml or whatever other AJAX response you want.
All was solved.