Hi, my name is Timo Ernst and I am a web expert.

Tutorial: A simple Twitter client with JQTouch

Posted on: August 4th, 2010 by Timo

Lately I have been doing a lot of coding for mobile devices, like iPhone or Android, but I was never really happy about the development environments. Objective C is a horrible and antique language while the Android SDK is quite nice (due to its Java roots) but does not give me the ability to create multi platform apps. So what’s left? Right. Web-technologies.

Luckily, I stumbled over a really nice framework called JQTouch which hat its roots in the JQuery library (as you probably already guessed). JQTouch enables the developer to create applications with some JavaScript and HTML usage without ever touching a weird iPhone compiler. It’s perfect for people who already have a decent amount of knowledge about these technologies and want to create mobile apps that run on multiple platforms.

In this mini-tutorial, we’ll create a simple Twitter app, which will display the tweets of a user. The final application is supposed to look like this:
JQTouch example screenshot of final version JQTouch example screenshot with twitter search results

All you need to create a simple application is:

  • JQuery
  • JQTouch
  • A text-editor or IDE of your choice. I like Netbeans due to its superior JavaScript support.
  • Apple’s Safari browser (Great for first tests since it behaves very similar to browsers on mobile devices)
  • The mobile devices you’d like to deploy for (for testing purposes)

Less blah, more code!

Let’s get started by creating the user-interface. This is entirely done in HTML. For the moment, you’ll neither need a lot of JavaScript, nor CSS. All you gotta do is:

  1. Create a simple HTML template
  2. Import the JQuery and JQTouch librarys
  3. Define the UI

A template that you can always use to start a new jQTouch project could look as follows:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Hello, jQTouch</title>

    <!-- include JQuery through Google API => Always have the latest version -->
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript"> google.load("jquery", "1.3.2"); </script>

    <!-- import JQTouch -->
    <script src="jqtouch/jqtouch.min.js" type="application/x-javascript" charset="utf-8"></script>

    <!-- Import JQTouch default style (iPhone look). Replace the string "themes/apple" with "themes/jq" for a neutral (black) theme -->
    <link type="text/css" rel="stylesheet" media="screen" href="jqtouch/jqtouch.css">
    <link type="text/css" rel="stylesheet" media="screen" href="themes/apple/theme.css">

    <!-- JavaScript goes here -->
    <script type="text/javascript">
      // Fire up JQTouch
      var jQT = $.jQTouch({
        statusBar: 'black'
      });
    </script>

    <!-- CSS styles -->
    <style type="text/css" >

    </style>
  </head>

  <!-- UI definition goes here -->
  <body>
  </body>
</html>

Hello World!

This markup doesn’t show anything yet if viewed in a web-browser, so let’s start adding some “Hello world!”-style info to it:

<!-- A simple JQTouch layout consisting of two views -->
<body>
  <!-- "Page 1" -->
  <div id="theform">
    <div class="toolbar">
      <h1>TweetMe</h1>
    </div>
    <ul class="rounded">
      <li>Hello World</li>
      <li><a href="#tweets">Go to view 2</a></li>
    </ul>
  </div>

  <!-- "Page 2" - Will contain the tweets found -->
  <div id="tweets">
    <div class="toolbar">
      <h1>Results</h1>
      <a class="button back" href="#">Back</a>
    </div>
    <ul id="results_ul" class="rounded">
      <li>This is page 2</li>
    </ul>
  </div>

</body>

Now, replace the empty <body></body> tags of our template with this UI definition and put everything into a new index.html file (together with the required libraries), then open it in Safari and you should already be able to see a simple user-interface in iPhone-look. You can click on the 2nd entry in the list and it should bring you to the “results” view. Click the back button on top and you should return to the point where you started. This is all handled through the JQTouch framework. Cool, eh?

JQTouch example screenshot 01 JQTouch example screenshot 02

In the BODY tag, you should see two DIV definitions, where each represents one view. The first one will be used to display a simple form for the user in order give him the opportunity to enter a Twitter user-name (currently there is just a place-holder with a Hello-World string and a link but we’ll change that in a second). After the “hypothetic form” (which doesn’t exist yet) was submitted, we want the app to “smoothly” slide to view 2 where the result data will be displayed.
Each DIV has an inner DIV with class “toolbar”. This is the blue header at the top of each view which also holds the back button. If you don’t want it, you can just remove that tag but I’d recommend to leave it there.
Also notice that both DIV’s have an id. This is important in order to easily switch between views. You can do this by simply adding a link, which references the id of the view to target via its HREF attribute with a ‘#’ character in front. So if you want to switch to a DIV/view which has the id “myview”, you can simply create a link which looks like this:
<a href="#myview">Go to the view</a>.
DAMN, that’s easy, isn’t it?

Defining the Twitter UI

So, let’s get started and replace the “Hello World” stuff with some serious markup. First of all we’ll replace the <ul> element, which holds the “Hello world”-content, with an input field and a button:

<ul class="rounded">
    <li><input type="text" placeholder="User name" name="username" id="username_input" autocapitalize="off" autocorrect="off" autocomplete="off"></li>
    <li class="arrow"><a href="#tweets">View tweets</a></li>
</ul>

In order to give the “View tweets”-button a look as it could be pressed, the surrounding list element gets the class “arrow”. This will display a nice little arrow at the right of the screen.

Now, if you hit the link, the app smoothly glides to the 2nd view. Since it may take a few seconds to load all tweets, we want to display a loading message to the user here:

<ul id="results_ul" class="rounded">
  <li>Loading...</li>
</ul>

These modifications get us the final version of the user-interface:
JQTouch example screenshot 03 JQTouch example screenshot 04

Calling the Twitter service

That’s it for the moment with HTML. Now we need some application logic to call the Twitter REST service and retrieve the data of the user. In order to get this done, all we need to do is to fire up an ajax call to:
http://api.twitter.com/1/statuses/user_timeline.json?screen_name=USERNAME
The result will be a JSON object as described in the Twitter API documentation. For the ajax call, we’ll use JQuery’s built-in ajax() method.

In order to accomplish this, we first must attach a click listener to the “submit”-button so we can fire the ajax call. To do this, we add an id to the anchor like this:
<a id="submitButton" href="#tweets">View tweets</a>

Then, we’ll set an init function, which should be called once the body has loaded:
<body onload="init()">

Finally, inside the init function, we can attach the event listener:

/**
 * Will be called after all the markup in <body> was loaded
 */
function init(){
  $("#submitButton").bind(clickEvent, function(e){
    getTweets();
  });
}

If the link is now triggered, the method getTweets(), which I’ll explain later, gets called. You might have noticed that the the .bind(event, function)-method gets a variable called clickEvent instead of the usually used string “click”. The reason for this is that some touchscreen-based devices, like the iPhone for example, do not trigger the “click”-event. Instead, they use “tap”. Thus, it is important to check the user-agent of the browser and examine, which event should be fired:

// Determine if iPhone, Android or Desktop OS and setup the right click-event ("tap" vs "click").
var userAgent = navigator.userAgent.toLowerCase();
var isiPhone = (userAgent.indexOf('iphone') != -1 || userAgent.indexOf('ipod') != -1) ? true : false;
clickEvent = isiPhone ? 'tap' : 'click';

The variable clickEvent is now globally available and can be used whenever a click/tap event on a link must be triggered or catched.

Regarding the ajax call itself, there is an important thing you have to know about the so called “Cross Domain Policy”. This is a security feature, which lets the website you’re currently viewing not call remote urls which are running on servers from a different domain than the website you’re looking at. In other terms: We cannot directly call the Twitter API unless you can deploy your mobile application to Twitter.com. There are various ways to work around this. One is to use Flash, which can ignore the cross domain policy. Since we cannot rely on the fact that every user has a Flash plugin (especially the iPhone boys out there), we’ll go for a server-side solution by simply creating a proxy service using PHP which tunnels the ajax call and thus does the API call for us. Since the PHP file will run on the same server the mobile app runs on, we can call this script easily via ajax. Sounds complicated? It isn’t. Believe me.

(Note: Of course, you can use any other server-side technology of your choice like J2EE or ruby. I personally like PHP, so I’ll go for that one but any other language will do the job too.)

Now, let’s create a new file called service.php, which accepts a url parameter (the url to the Twitter API), calls it and then dumps the response back to its caller:

<?php
  $url = $_GET["url"];
  $handle = fopen($url, "rb");
  $content = stream_get_contents($handle);
  fclose($handle);
  echo $content;
?>

Now, we can call this script via the JQuery method ajax():

/**
 * Does an ajax call and retrieves the tweets of the user specified in the
 * input field "username_input"
 */
function getTweets(){
  // Show a loading message
  var results_ul = document.getElementById("results_ul");
  results_ul.innerHTML = "<li>Loading...</li>";

  // Get the username from the input field
  var username = document.getElementById("username_input").value;
  // Prepare the Twitter url, so it can be passed as a GET parameter
  var twitterUrl = escape("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=" + username);

  // Do the ajax call
  $.ajax({
    url: "service.php?url=" + twitterUrl,
    // Callback (onsuccess)
    success: function(d, status, req){
      // Convert the JSON result to an array of tweets
      var tweets = eval('(' + d + ')');
      // Display the tweets
      showTweets(tweets);
    },
    // Error handler
    error: function(req, status, err){
      // Alert the user that something went wrong
      var results_ul = document.getElementById("results_ul");
      results_ul.innerHTML = "<li>An error occured. Tweets could not be loaded<br>"+status + ": " + err + "</li>";
    }
  });
}

If the ajax call fails, an error message is being displayed to the user. On success, the method showTweets(tweets) will be called passing over an array of tweets. We’re almost there! Can you smell it already?

The last step is simple. Just iterate over the result array and dump out the tweets:

/**
 * Outputs the received tweets to the user-interface
 * @param tweets The tweets as an array. Each element represents one tweet and can be accessed via tweets[i].text
 */
function showTweets(tweets){
  var results_ul = document.getElementById("results_ul");
  results_ul.innerHTML = "";

  if (tweets.length <= 0){
    results_ul.innerHTML += "<li>User not found. Please press 'back' and try again.</li>";
  }
  else{
    for (var i=0; i<tweets.length; i++){
      results_ul.innerHTML += "<li>" + tweets[i].text + "</li>";
    }
  }
}

Update: The "proxy-technique" shown here is not the only way to bypass the cross domain policy. Another possibility is to use JSONP, which allows ajax calls to services on other domains without any backend-service (Thanks to Luis for the hint!) through a technique which retrieves the JSON data by abusing the <script> tag, which seems to ignore the cross domain policy. However, if you choose to use this technique, you have to be aware about two things:

  1. The server must support JSONP. Twitter can handle it but you might encounter a service which cannot. In this case you'll have to fallback to a proxy solution as shown here.
  2. Since it is possible to do XSS attacks (= Cross site scripting attacks) through JSONP, it is strongly recommended to use jQuery's ajax() method by passing the additional parameter dataType: "jsonp". This will add JSONP support to the ajax call and also automatically evaluate the result as JSON, so no extra eval(data) is necessary! (I am not 100% sure if jQuery handles the XSS issue correctly when evaluating the JSON data, so be careful!)

Simulating a form-submit event

If you run your app now, you should already be able to see a first working result. Enter a Twitter username, hit "View tweets" and you should encounter a list of what that person had for breakfast today. However, if you just hit your enter key instead of clicking on the search-link, nothing will happen. That's because we haven't taken care of that yet, so let's get this done in order to make this thing perfect. The easiest way to do is to simply attach a listener to the input field and check if the enter key was pressed:

/**
 * Event-listener. Gets called if the user presses a button on his keyboard
 * in the input field.
 * @param keynum The pressed key (as an ASCii value)
 */
function keydown(keynum){
    // 13 = The ASCii value of the return key on your keyboard
    if (keynum == 13){
        $("#submitButton").trigger(clickEvent);
    }
}

Don't forget to register the listener:

<input onkeydown="keydown(event.which);" type="text" placeholder="User name" name="username" id="username_input" autocapitalize="off" autocorrect="off" autocomplete="off">

There are some important things you have to know about this:

  1. Don't use a <form> element because a) it won't validate and b) it simply won't work because ordinary form submit events reload the full page. We don't want that.
  2. In order to switch to view #2, you shouldn't do something like:
    window.location.href="#tweets";
    It will mess up jQTouch's navigation logic. Always define a link for this purpose and trigger it using the .trigger(event)-method.
  3. $("#submitButton").click(); will not work :-)
  4. It is important that you take care about this issue! Mobile phone users usually use a virtual keyboard. Once they entered a username, they often press "return". If you don't catch this event, nothing will happen and the virtual keyboard will remain while the visitor has to hide it manually and then press the "View tweets" link. This is a usability nightmare for sure.

The final app

If you now search for the user "timo_ernst" for example (or any other Twitter user), you should see some like this:
JQTouch example screenshot with twitter search results

Now, that was damn easy, wasn't it?
Check out the full running thing at http://www.timo-ernst.net/tweetme.
Download the full source as a ZIP file here.

To prove that this app runs across multiple platforms, I made a photo of it on iPhone OS 4.0 (right) and a HTC Desire with Android 2.2 "Froyo" (left):

jQTouch working on iPhone and Android

Am I the only one who thinks that the Desire's AMOLED display is truly magnificent? :-)

Note

I am aware of the fact that there is already a Twitter app out there for WebOS called "TweetMe". Since I just needed a quick name for this demo application, I choose the first best thing that came to my mind. Of course, this demo is not meant to be a real, commercial project. Its only purpose is to demonstrate the capabilities of JQTouch and not to be a competitor to WebOS TweetMe. If the author of that app is offended by this in any way, please contact me and I'll rename this thing. At the moment, I simply feel a bit to lazy :-)

TwitterFacebookShare
Tags: , , , , , , ,

73 Responses

  1. ikram says:

    Hi Timo,
    I’m interesting in mobile application development.
    mainly I’m web and graphic designer I know about HTML, CSS, JAVA SCRIPT, JQUERY and related printable software.
    So what you think i’m handling the mobile application. I know .NET language and C, C++ used in iphone app. I hope you understand my situation
    Give me some idea and brief about iphone.

    Thumb up 3 Thumb down 0

  2. Timo says:

    @ikram
    Hi,
    sorry but I’m currently not interested.

    Poorly-rated. Like or Dislike: Thumb up 0 Thumb down 4

  3. ikram says:

    ok

    what is the first learning step for mobile app. please share with me some link like mobile app tutorials and learning book(pdf). .

    Thanx.

    Thumb up 0 Thumb down 0

  4. Timo says:

    That depends on the technology you’d like to use.

    I usually start with the online documentation of the library/frameworks (Google search).
    Then, buying an appropriate book on amazon would be a logical next step (just use amazon search).
    If available, I also often watch screencasts but those are rare.

    Thumb up 0 Thumb down 2

  5. RASEL says:

    Hi, i am new in JQuery and JQTouch.

    $('#dataTable &gt; tbody:last').append('<a href="#report" rel="nofollow">' + e.hrn + '</a><a href="#report" rel="nofollow">' + e.name + '</a><a href="#report" rel="nofollow">' + Date_toYMDString(e.adm_date) + '</a>');

    I am creating dynamically runtime table rows. then i am adding click event on these rows. which should call an method to get some data for new DIV(#report). i am trying both way..but those some times can work and sometimes not working, i mean click event are not listening always… in my mobile safari browser.


    $("#eTable").delegate("tr", "click", function(event){

    });

    $("#dataTable tbody tr").live('click', function() {

    });

    please what is problem??

    Thumb up 1 Thumb down 1

  6. RASEL says:

    each row contains three div. each div contains i want to click my row go to the report div and also need to execute a mehtos. beacuse the report div contain diifrent data based on selected row.

    Thanks . please need help.

    Thumb up 1 Thumb down 1

  7. Timo says:

    I suggest you post this at http://www.stackoverflow.com

    Thumb up 0 Thumb down 2

  8. Varun Khandelwal says:

    Hi Timo,

    Just one question.

    If we are to make this application without using Browser i.e standalone app, then using which technology we can do that.

    Thumb up 1 Thumb down 1

  9. Timo says:

    Hi Varun,
    you should use phonegap: http://phonegap.com/

    Thumb up 1 Thumb down 2

  10. Varun Khandelwal says:

    Hi Timo,

    Thanks for your prompt reply.
    I am planning for an app which will have thin client like any mobile banking software, and in server side there will be a java code which will run on tomcat server. The server side code will still be done by me and i won’t be using web service.
    Can i still go ahead with phonegap?

    Regards,
    Varun

    Thumb up 1 Thumb down 1

  11. Timo says:

    Phonegap has nothing to do with server side logic. It’s pure client-side technology to wrap HTML5-apps into native apps.

    Usually, I’d suggest to bind server and client via a web service but since you stated that you wouldn’t be using a web service, how would you bind both together?

    Thumb up 0 Thumb down 2

  12. Varun Khandelwal says:

    Is there no other way to do this without using web service?

    Thumb up 0 Thumb down 1

  13. Timo says:

    Hm, well you could provide the app in a static way from the web server by adding all the content to the app itself. That has some downsides though:
    1. No dynamic (generated) content
    2. The app is on the server, not on the phone
    3. Due to (2) you cannot use it in offline mode

    Please also keep in mind that I don’t know anything about your project or your setup so the suggestions that I make may not comply with your requirements.

    Thumb up 0 Thumb down 2

  14. Varun Khandelwal says:

    Thanks alot.
    But Just one last question.

    will web service make the app slow?
    and is it easy to implement web service and then call that web service from tool like PhoneGap.

    Thumb up 1 Thumb down 1

  15. Timo says:

    Well, you have to poll your server somehow to get your data or not?
    So performance doesn’t depend on having a web service or not but rather on (A) the speed of your server and (B) the efficiency of your implementation.

    Well, I personally find web services to be easy to implement. I don’t know what and how much you know about that topic.
    Calling a service from your app is very simple. Just do a normal ajax call with jQuery (see http://api.jquery.com/jQuery.ajax/) and you’re done.

    Thumb up 1 Thumb down 2

  16. Matt says:

    This is a great howto.

    I wonder if it’s possible to have some alter in your phone that when you have a tandard account you want to check… a “popup” or whatever is shown in your screen.

    I wonder if such app from phonegap can run in the background for this… would be awesome!

    Thumb up 0 Thumb down 2

  17. sai says:

    hi Timo,
    Can u give me sample example on web services with ksoap2 on android platform of client side using phonegap.

    Thumb up 0 Thumb down 1

  18. [...] CSS, and JavaScript. You can find lots of tutorials about this on the Internet, e.g. this one: Tutorial: A simple Twitter client with JQTouch In fact, I’m using a slightly modified version of the Twitter client described in the link to [...]

    Thumb up 1 Thumb down 0

  19. [...] Tutorial: A simple Twitter client with JQTouch [...]

    Thumb up 1 Thumb down 0

Leave a Reply