How to do an AJAX search with jQTouch, Part 2

In the last installment of How to do an AJAX search with jQTouch we looked at how to setup a jQTouch interface with the goal of performing an AJAX search. In this article, we will write the necessary JavaScript to perform that AJAX search, as well as a PHP script to respond to those calls.

This article assumes you have read the first part of this series.

Before we start, we should take a step back and consider what we’re about to do. Our Searcher app has three parts:

  • the client-side jQTouch UI,
  • the client-side jQuery AJAX calls,
  • the server-side PHP script (that could easily be backed by a database)

At this point we have finished the jQTouch UI. However, instead of immediately moving on to writing the jQuery AJAX calls, let’s start with the PHP script instead. This will help us understand our AJAX calls when it comes time to write them.

The PHP Script

Since our PHP script will be performing a search, let’s create a file called search.php and add a single line of boilerplate:

<?php

There’s no need for an end tag. In fact, in files containing only PHP, it is recommended that you do not include an end tag:

For files that contain only PHP code, the closing tag (“?>”) is never permitted. It is not required by PHP, and omitting it prevents the accidental injection of trailing white space into the response.

Our Searcher app needs to search for something, so let’s pretend it’s an interface for a music player and we’re searching for songs. In order to express that idea into PHP code, we need the following elements:

  • a Song class to hold the artist name and the title,
  • an array holding a bunch of Song objects,
  • a function for searching the Song array,
  • a way to get a search value from the AJAX request,
  • a way to set the MIME type to JSON,
  • a way to encode our Song array as JSON

First, we’ll need a class to hold the songs (place this starting at line 3 in search.php):

3
4
5
6
7
8
9
10
11
class Song {
    public $artist;
    public $title;
 
    public function __construct($artist, $title) {
        $this->artist = $artist;
        $this->title = $title;
    }
}

Let’s break it down for those not familiar with PHP classes:

  • at line 3, we declare the class name
  • at lines 4-5, we declare two public fields to represent the artist’s name and the title of the song,
  • at lines 7-10, we declare the class constructor that we use to initialize the two fields of a Song object

Now that we have a way to model songs in our PHP script, we need to make an array of some dummy songs that we can query using AJAX:

13
14
15
16
17
18
19
$songs = array(
    new Song("Weezer", "Say It Ain't So"),
    new Song("Weezer", "Undone"),
    new Song("Cake", "Meanwhile, Rick James..."),
    new Song("The Stars", "Ageless Beauty"),
    new Song("Roy Orbison", "In Dreams")
);

Now we have something of a faux database setup. How will we search it? Why, with a search function, of course! Let’s write that now:

21
22
23
24
25
26
27
28
29
30
31
32
33
34
function search($songs, $value) {
    if (empty($value))
        return $songs;
 
    $matches = array();
    foreach ($songs as $s)
    {
        $matchArtist = stripos($s->artist, $value) !== false;
        $matchTitle = stripos($s->title, $value) !== false;
        if ($matchArtist || $matchTitle)
            $matches[] = $s;
    }
    return $matches;
}

So what does this function do? Let’s take a look line-by-line:

  • at lines 22-23, we check to see if the search value is empty (i.e. an empty string or null). If that’s the case, then we just return all the songs
  • at line 25, we declare the $matches array. This will contain all the songs that match the search value $value
  • at line 26, we use a foreach loop to iterate through all the Song objects in the $songs array
  • at lines 28-29, we check to see if the artist name or song title contain the search value $value
  • at line 30-31, we add the Song object to the $matches array if it matches the artist name or song title
  • at line 33, we return whatever matches (if any) we have found

Ok, so now we have a Song class, an array of Song objects, and a function that searches that array. What’s left in our PHP script? Well, as it stands, we have no way to interface with it. What we need to do now is have some sort of way to respond to the AJAX GET request that our Searcher app will send. To do that, we harness the awesome power of the $_GET superglobal:

36
37
$value = $_GET['value'];
$matches = search($songs, $value);

On the first line, we extract “value” parameter from the $_GET superglobal and assign it to the $value variable. The second line runs our search function on the $songs database and searches for songs that have an artist or title that contains the $value string.

We’re almost there! At this point we’ve managed to get an array of Song objects that match the passed search value. All we need to do now is return that PHP array of objects as a JSON-encoded array of objects. Let’s do that now:

39
40
header('Content-Type: application/json');
echo json_encode($matches);

The first line sets the the MIME type of an HTTP response. MIME types are a sort of meta data that is used to describe what sort of content is being returned. In this case, we are telling jQuery (or whatever client that issued the request) that we are returning content that is JSON formatted. The second line is a built-in PHP function that converts PHP types into a string containing their JSON counterparts. Basically, it allows us to encode our PHP objects into JavaScript and allow us to access them in a nearly identical way:

// PHP
array(
    new Song("Artist 1", "Title 1"),
    new Song("Artist 2", "Title 2")
);
 
// Becomes... (after json_encode)
// JavaScript
[
    { artist: "Artist 1", title: "Title 1" },
    { artist: "Artist 2", title: "Title 2" }
];

And we’re done the PHP script! If we want to test it, we can load execute the PHP file on our server and try different search values. For example, entering this URL should return a JSON array with two Song objects:

// URL
http://example.com/jQTouch-ajax-search/search.php?value=Weezer
 
// Response
[{"artist":"Weezer","title":"Say It Ain't So"},{"artist":"Weezer","title":"Undone"}]

The jQuery AJAX calls

The finish line is now in sight. We’ve successfully written our jQTouch UI and our PHP script. The last thing we need to do is write some jQuery AJAX calls to execute our search and load the results into our UI. In order to do that, we need to do the following:

  • listen for the submission of the search form in the jQTouch UI
  • when the submission happens, get the search value from the form and set it as a parameter in an AJAX call to search.php
  • register a callback that will populate the jQTouch search results when the AJAX call completes

Let’s start with listening for the submit event on the search form. First, we’ll need to create a new JavaScript source file search.js and fill it with the following boilerplate:

(function($){
 
    // Put code here.    
 
})(jQuery);

What this boilerplate does is give our JavaScript script its own context so that can minimize leaking variables into the global JavaScript namespace. It also gives us access to the jQuery object in the convenient $ form, regardless of whether or not “no conflict” mode is enabled.

Recall in part 1 we defined an HTML search form that looked like this:

1
2
3
4
5
6
7
8
9
10
11
12
<form id="search" action="">
    <div class="toolbar">
        <h1>Search</h1>
        <a href="#" class="back">Back</a>
    </div>
    <ul class="rounded">
        <li><input type="text" name="search-text" placeholder="Search" id="search-text" /></li>
    </ul>
    <ul class="edgetoedge" id="search-results">
        <li class="sep">Results</li>                
    </ul>
</form>

Note that on line 1 we defined the id of the form as search. We’ll use that to find the form and register a handler for its submit event so that we can take action when someone tries to perform a search using the jQTouch UI.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
(function($){
 
$(function(){
 
    $("#search").submit(function(event, info) {
        var text = $("input[id=search-text]", this);
        text.blur();
 
        var results = $("#search-results", this).empty();
        results.append($("<li>", {
            "class": "sep",
            text: 'Results for "' + text.val() + '"'
        }));
 
        $.get("search.php",
            { value: text.val() },
            function(data) {
                $.each(data, function(i, song) {
                    var str = song.artist 
                        + " - "
                        + song.title;
                    $("<li>")
                        .text(str)
                        .appendTo(results);
                });
            }
        );
 
        return false;       
    });
 
});
 
})(jQuery);

There’s a lot there, so let’s break it down line-by-line:

  • starting at line 3 and ending at line 32 we have the jQuery ready handler which is run once the DOM has finished loading
  • starting at line 5 and ending at line 30 we bind a submit event handler to the submit event for the #search form
  • at lines 6-7, we retrieve the search-text element, assign it to a variable (for later use on line 16), and then blur (i.e. deselect) the element so that the iPhone keyboard will go away
  • at lines 9-13, we clear any previous items in the list that may be hanging around from a previous search and then load in a new separator (“sep”) that contains the search value
  • at line 15-27, we perform our AJAX GET request to search.php with the value of the search text field as our value parameter (line 16) and a callback that adds the results to the list (lines 17-26)
  • finally, at line 29, we return false to prevent the default form behaviour (i.e. submitting the form) from being carried out

And we’re done. All we need to do now and include search.php in the header of index.html so that it’ll be run:

12
<script src="search.js" type="application/x-javascript" charset="utf-8"></script>

Conclusion

In this, the final installment of How to do an AJAX search with jQTouch, we finished off the example application we started in the first part of this series.

In part 1, we covered building a UI using jQTouch. In part 2, we helped visualize our problem by pretending that we were writing a front-end UI to a server-side music player. To do that, we jumped into server side programming with PHP to write a script to serve us JSON-encoded Song objects. Once we had that setup, we moved back into JavaScript. In order to make use of the PHP script, we wrote a jQuery handler to respond to a jQTouch form submission. The handler, once triggered, issued an AJAX call to the PHP script to pull down the appropriate Song objects for display in our UI.

What Now?

With respect to the goals of this tutorial, nothing. However, if you want to pimp up the application a bit more, some things you could do are:

  • Add genres and albums to the PHP Song object and then make the jQTouch UI menu have two additional options: Genres and Albums
  • Try to make a Now Playing sub-menu that is activated when a Song is picked from the Search screen

Source

The source code I have written in this article is public domain, and you are free to do what you will with it. Here is a zip of the source, along with the required jQTouch source. It should work pretty much right out of the box.

24 Comments so far

  1. Edmundo Junior on September 1st, 2010

    Awesome tutorial, works great for me! Until…

    There’s any way to wrap up the results with a link? I’m trying to do something like this:

    $songs = array(
    new Song(“Controle”, “Neozinho”),
    );

    But don’t work! I do not now PHP so well =/
    Can you help me? What do I do?
    Thanks!

    Ps.: sorry for the bad english;

  2. Edmundo Junior on September 1st, 2010

    This is the code, now right, hehe.

    
    $songs = array(	
    	new Song("Controle", "Neo Light"),
    );
    
  3. cdmckay on September 1st, 2010

    @Edmundo Junior:

    If you want to wrap it in a link, you’ll probably need to add a new field to Song (maybe called $url) and then make the jQuery code create a link if that field isn’t empty.

    I suggest grabbing a book on PHP :)

  4. Edmundo Junior on September 1st, 2010

    @cdmckay I’m grabbing a book called internet right now :)
    Again, excellent tutorial! Thanks for the fast reply!

  5. morgan on September 16th, 2010

    Hi,

    This code sample doesn’t work for me, the search always return undefined, undefined in the result list.
    It seems that this part of code doesn’t work:

    $.get("search.php",
        { value: text.val() },
        function(data) {
            $.each(data, function(i, song) {
                var str = song.artist 
                ...

    I put my “search.php” file in the same place as the other files.
    Am i doing sthing wrong?
    Thanks in advance.
    Morgan

  6. cdmckay on September 16th, 2010

    Try downloading the code that I used (and tested):
    http://cdmckay.org/files/jqtouch-ajax-search-part2.zip

    It may be a PHP version issue. I was using 5.3. It may not work with previous versions.

  7. morgan on September 16th, 2010

    That’s good, that was a php issue. Thank you very much! I just discovered jQTouch and webapps and your sample was very useful for me.

    What would you advise me to do in order to accomplish the following:

    I want to have a 3 depth cascading links in unordererd lists. I’m not sure I’m clear so I make a draft:

    section1 > link1>
    link2>
    … > linkA > content1
    linkB > content2

    Each time I click a link, a php request to a database is made to get a list of datas that will populate my ul and will be links to launch other php requests … until I reach a final description.
    I hope it won’t bother you to respond to such strange thing.
    Thank you.
    Morgan.

  8. thor on October 26th, 2010

    Script doesnt work for me either, says search results are undefined, tried the other version posted but didnt help. ive been trying to make a search (without reloading the page) for 3 days now, was hoping this would be it, its almost exactly what im looking for. Good job anyways.

  9. thor on October 27th, 2010

    So this only works with PHP 5.3? Should mention that in the tutorial, how do I display the results then? When I do alert(data) I see that its grabbed the data, but no idea how to display it. evalJSON(data) or parseJSON(data) doesn’t work either.

  10. cdmckay on October 27th, 2010

    @thor:

    The JSON is already parsed. The “data” object is the JSON object.

  11. steve on November 5th, 2010

    Is there a way to have the results appear dynamically as I’m typing? Like how iTunes search works.

  12. cdmckay on November 5th, 2010

    @steve:

    If you listened for the “onKeyUp” event (check the jQuery documentation) and fired your AJAX request then, you could simulate that behaviour.

  13. Sebastian on January 7th, 2011

    Just thanks, well coded with clear explanations.

  14. steven on February 23rd, 2011

    Great tutorial, just one thing please…

    You are currently heardcoding the results in an array and searching the results in the page.
    How can I query a database instead please?

    thanks

  15. John P on February 28th, 2011

    Thanks a million. People like you make the world a better place. :-)

  16. cdmckay on February 28th, 2011

    @steven:

    You’ll need to grab your records from a database and then load them into Song objects.

    For example:

    $songs = array();
    $db = new mysqli( ... );
    $result = $db->query( ... );
    while ($row = $result->fetch_assoc) {
      $songs[] = new Song($row['artist'], $row['title']);
    }

    If you want something more sophisticated, have a look at an ORM like Doctrine or Propel.

  17. Randy on March 28th, 2011

    I keep getting “Undefined – Undefined” too.
    I am using PHP 5.3.6…I even downloaded your files and tested them, and get it. Any ideas?

  18. Randy on March 28th, 2011

    nevermind…i found my error (was using old jquery call instead of
    ” google.load(“jquery”, “1.4.2″); “

  19. Kannan on April 29th, 2011

    Hi Morgan,

    Changing $.each to:
    $.each(JSON.parse(data), function(i, song) {
    works for me. Otherwise it behaves like a string.

    Kannan

  20. moffie on July 30th, 2011

    I’m sorry for my bad english.
    Here is my question: is it possible to give the results a specified link?

    example:
    I would like to search for Weezer, and end up with a clickable result “Weezer – Say It Ain’t So” that points me to a http://example.com

    Is it possible?
    Can you provide the code?

    Thanks

  21. moffie on July 30th, 2011

    I forgot to say, obviously, I would like to have a different link for each different result.

    Thanks again

  22. galo on October 4th, 2011

    Hi, thanks for the tutorial, it works. I am on a task, i dont need to search i just need to show a mysql table when i push over a button. Your tutorial almost gettin me there, how can i do this?

  23. Kamal on October 15th, 2011

    Hi,
    Nice tutorial,

    Please, what did you use (tools IDE,..) to develope this example and how it was simulated ?

    2)How it was reloaded the web page in iPhone or iPad ?

    3) I see php here, does iPhone or ipad or a simulator understand php ?

    Thanks
    Your help is appreciated.

  24. cdmckay on November 28th, 2011

    @Kamal:

    I used NetBeans to develop it and used my iPod Touch to run it over my local network. The page was served using Apache via XAMPP on Windows. You are right, iOS does not natively run PHP. The PHP is run on the server side.

Leave a reply

ERROR: si-captcha.php plugin says GD image support not detected in PHP!

Contact your web host and ask them why GD image support is not enabled for PHP.

ERROR: si-captcha.php plugin says imagepng function not detected in PHP!

Contact your web host and ask them why imagepng function is not enabled for PHP.