Qtip’s biggest issue is that it simply isn’t documented very well. We use Qtip to do a variety of slick things at Jokels, but figuring out how to do them took a significant amount of time of digging through the qtip documentation and Googling qtip examples. To save you some time, here are some the slicker features of Qtip and how to use them:
The meat of the code is in the “content” object. The “text” attribute is displayed until the “ajax” object can be loaded. The “/qtip/joke/” page is a very simple view which has some simple joke information and takes a query parameter of ‘id’ for the joke. Once this page is loaded it’s displayed in the Qtip.
Specifying More Complicated Content
Another cool use of Qtip is that it can take a jquery element and use that as it’s element. This isn’t used on Jokels, but I have used this in a side project as a way to have a generalized way of grabbing a form element that was hidden and display it to the user when certain conditions are met (e.g. a validation condition comes up that requires additional information from the user):
The only change for the Qtip section from the previous gist that is that we add a .clone() to make a copy of the content so Qtip will leave the original section alone. The meat of this gist is the second section: we’re using the live function on page load so that any form field that’s created inside of a qtip div will automatically have a change event handler attached that finds the matching field in the form and updates it to match its own value.
Displaying Validation Messages
Another really slick use of Qtips that I came across recently is to show validation messages on forms. Here, we get the error message and pop it up in a qtip on the form field:
There’s nothing terribly exotic about this example, except for some of the options that after content. By adding the “ready: true” attribute to the show object, we’re telling Qtip to pop up the tip on page load. By giving a null target we’re telling Qtip to never show the message again after the initial page load. The “hide” object tells qtip to hide the message on the “blur” event (focus lost event) for the form field. So the validation message will stay on the form field until the user focuses in and exits the given form field (at which point we can assume they’ve at least had the opportunity to address the issue).
Viewport and Effect
I mentioned before that Qtip isn’t documented well, and hopefully this blog post has shown some cool uses of Qtip that maybe wouldn’t immediately jump out of the tutorials and doc available on the project website, but I wanted to quickly show two options that are critical to a sucessful use of Qtip in your project. Viewport just tells Qtip what to consider the bounds of where it can show a Qtip. So by specifying $(window), Qtip won’t show any pop-ups that will be outside of the browser’s current view. Effect is documented well on Qtip’s site, but the thing most people are going to want to use for effect isn’t, which is simply to turn off all of Qtip’s effects and just show the pop-up, which can just be accomplished by setting the attribute to “false”.
Almost assuredly you’ll find Qtip a fantastic tool for your website or latest project. It’s documentation may leave a little to be desired in terms of organization and comprehensiveness, but that’s only because it’s such a fantastic, versatile tool that it’s difficult to document all of its features.
I fully intend to come back and write a blog post on this, because it was the most exciting two hours of Ruby coding in my life, but for the meantime here’s a demonstration of embedding a joke from Jokels.com:
I learned the hard way JQuery Mobile works best when you stop fighting its static nature and allow it to provide a dynamic feel as much as possible. For the full version of Jokels, whenever you click the “random joke” button, a new joke’s HTML is dynamic loaded and inserted into the main page to replace the old one, so my first attempt at the mobile site did the same:
Here we use JQuery Mobile’s showPageLoadingMsg() and hidePageLoadingMsg() along with JQuery’s fadeIn and FadeOut to hide the page while a new Joke’s DOM is pulled in and the JQuery Mobile effects are applied manually. Not only is this more likely to break than JQuery Mobile’s navigation but it also means we can’t use certain JQuery Mobile effects which don’t support manual creation, like button groups.
The second pass at this is was much simpler and robust. Instead of trying to do our own AJAX loading we let JQuery Mobile do the work for us by dynamically creating a link to a random joke each time the mobile page is loaded:
We don’t include the random joke link in the page creation since JQuery Mobile caches pages already visited: this means including the static link in the page HTML would create a cycle if we managed to loop around to a previously visited joke in a given user’s session.
Page caching brings up another big gotcha with JQuery Mobile: old page DOMs stick around after navigation. This means that when you’re trying to use a JQuery selector to get a given element that may be on past pages, you need to make sure to select the current “page”‘s element instead of a cached one. We do this by looking for the class “ui-page-active.” This is how we set the upvote button to a pressed state and update the vote score, for example:
The final big issue with JQuery Mobile is that it doesn’t support query params. Ostensibly this is to support page caching: the theory being that “pageA.html?a=1” wouldn’t differ dramatically from “pageA.html?a=2”, so JQuery Mobile strips out query params and treats both links as identical. Obviously, this isn’t necessary true. For example, our leaderboards use query parameters to change whether Users or Jokes are being shown, by what criteria they’re sorted and for what time frame they’re being considered. This means that the same page with different query params can be dramatically different, so we need some way to support query parameters. One way to get around this is to add the ‘data-ajax=”false”‘ attribute to any links with query parameters, but this loses the beautiful AJAX navigation model. For the leaderboards we found a really simple solution: embed query parameters in the path using Rails’s dynamic segments routing. So for our leaderboard links, we just use this snippet in our routes.rb:
Then, in our Leaderboard_helper class we have this small function to get a link to a given leaderboard:
This allows us to still have static leaderboard pages using our query parameters, but use distinct paths so Jquery Mobile treats them as independent pages and loads them using its Ajax model.
JQuery Mobile has a few minor hang-ups. But combined with mobile-fu, it allowed us to get a functional mobile version of Jokels.com much quicker than anyone with our mobile experience has the right to do so.