I recently had to integrate search capabilities into a website I worked on. I chose to use the Google AJAX Search API. I needed the form field display to be very customized and clean. I do leverage the Dojo Javascript Toolkit to help with the boilerplate DOM and event stuff.

Search Form

The first thing you need to do is sign up for a new key:

Sign-up for an AJAX Search API Key

Once you get the key, you’re ready to start coding your own custom search form.

Begin by adding the the following to your <head> tag:

<script src="http://www.google.com/jsapi?key=<KEY GOES HERE>" type="text/javascript"></script>

Since my example uses Dojo, you need to include Dojo for my code to work. If you don’t already use Dojo, you can simply include it by adding the following to the <head>:

<script src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js" type="text/javascript"></script>

Next we need to add our code that performs the search. First tell the Google API to load the search API:

<script type="text/javascript">
google.load("search", "1", {"nocss":true,"nooldnames":true});

Next we need to initialize our page when the page loads:

dojo.addOnLoad(function(){
    var results = dojo.byId("results");
    var cursor = dojo.byId("cursor");
    var ws = new google.search.WebSearch();
    ws.setNoHtmlGeneration();

Be sure to set the domain you want to search. The LARGE_RESULTSET will return the maximum number of results Google allows, which is usually 8 results.

    ws.setSiteRestriction("example.com");
    ws.setResultSetSize(google.search.Search.LARGE_RESULTSET);

Next we need to tell the WebSearch object the function we want called after the results are returned. The 3rd argument to setSearchCompleteCallback() is an array with a reference to our WebSearch instance. This array gets passed to our callback function when the callback is fired.

    ws.setSearchCompleteCallback(null, function(w){
        if(!w.results){return;}
        results.innerHTML = "";
        cursor.innerHTML = "";
        var d = dojo.doc.createElement("div");
        results.appendChild(d);
        for(var i=0,len=w.results.length; i&lt;len; i++){
            var r = w.results[i];

Our WebSearch object has a createResultHtml() function that creates an the DOM nodes of our result, but it adds a bunch of crap and forces the result to open in a new window. So, to fix that, we use Dojo to go clean up the nodes before adding them to the page.

            w.createResultHtml(r);
            if(r.html){
                var n = r.html.cloneNode(true);
                dojo.query(".gs-visibleUrl", n).forEach(function(p){
                    p.parentNode.removeChild(p);
                });
                dojo.query(".gs-watermark", n).forEach(function(p){
                    p.parentNode.removeChild(p);
                });
                dojo.query("a", n).forEach(function(p){
                    if(p.getAttribute("target")){
                        p.removeAttribute("target");
                    }
                });
                results.appendChild(n);
            }
        }
        if(w.cursor){
            var cn = dojo.doc.createElement("div");
            cn.className = "gsc-cursor";
            var label = dojo.doc.createElement("div");
            label.innerHTML = "Pages:";
            label.className = "label";
            cn.appendChild(label);
            for(var i=0, len=w.cursor.pages.length; i&lt;len; i++){
                var pn = dojo.doc.createElement("div");
                pn.className = "gsc-cursor-page";
                if(i == w.cursor.currentPageIndex){
                    pn.className += " gsc-cursor-current-page";
                }
                pn.innerHTML = w.cursor.pages[i].label;
                pn.idx = i;
                dojo.connect(pn, "onclick", function(evt){
                    ws.gotoPage(evt.target.idx);
                });
                cn.appendChild(pn);
            }
            cursor.appendChild(cn);
        }
    }, [ws]);

If you want to execute a search when the page loads, then you can fire execute() with the criteria.

    ws.execute("");

Finally we need to wire up the search button and form. We don’t care about the event details, we just want to execute the search for the current value in the search criteria field.

    function query(evt){
        dojo.stopEvent(evt);
        ws.execute(dojo.trim(dojo.byId("searchCriteria").value));
    }
    dojo.connect(dojo.byId("searchButton"), "onclick", query);
    dojo.connect(dojo.byId("searchForm"), "onsubmit", query);
});
</script>

In the body of your page, add the following markup to define the form:

<div>
    <form id="searchForm">
        <input type="text" autocomplete="off" id="searchCriteria" value=""/>
        <a href="#" id="searchButton"><span>Search</span></a>
    </form>
</div>
<div id="results"></div>
<div id="cursor"></div>

For clarity, I removed all styling. One thing you’ll notice is the “Search” button is an <a> tag instead of an <input> tag so that it could be more easily be styled.

Aside from our text field and search button, there are some CSS styles you can tweak for the search results and pagination:

<style type="text/css">
.gs-result{padding:6px 0;}
.gsc-cursor{display:inline;padding:10px 0;}
.gsc-cursor .label{color:#000;display:inline;font-weight:bold;margin-right:8px;}
.gsc-cursor-page{cursor:pointer;color:#00F;display:inline;margin-right:8px;
text-decoration:underline;}
.gsc-cursor-current-page{color:#000;font-weight:bold;text-decoration:none;}
</style>

That’s all there is to it. Load the page up and do a search!

Search Results

6 Comments

  1. Great article Chris … Just in case you didn’t notice, in Dojo 1.2 there is a google.smd which defines all the public facing Ajax API’s google offers through Dojo’s RPC system.

    var goog = new dojox.rpc.Service(dojo.moduleUrl(“dojox.rpc”,”/SMDLibrary/google.smd”);
    goog.webSearch({ q:”Dojo CB1″ }).addCallback(function(response){ … });

    as well as Several dojox.data DataStores to wrap each service in the dojo.data API

    So as always, with Dojo you have the choice of “raw communication” with google (as you’ve outlines), a mixable RPC Service for Deferred communication, or “the dojo.data” way as options available to you.

    Comment by Peter Higgins — September 11, 2008 @ 1:34 pm

  2. Thanks for the tip! For this project, we decided to stick with Dojo 1.1.1. I should update this post after Dojo 1.2 becomes GA.

    Comment by Chris Barber — September 11, 2008 @ 5:06 pm

  3. It may also be worth using Dojo from the Google CDN:

    http://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js

    Comment by James Burke — September 14, 2008 @ 3:52 pm

  4. I need to know how to make this post the searhc results to another page, using method=”post”. What I did was generate the search button on the form page and put the search code on the query page. But this does not seem to work. Any ideas?

    Comment by Nkonye Oyewusi — March 4, 2009 @ 10:22 am

  5. You could probably hack it to post back on search, but that kind of defeats the purpose. It’s Ajax search which means you can search without reloading the page. Google has another API for doing searches, but I don’t the name of it off the top of my head.

    Comment by Chris Barber — March 5, 2009 @ 1:35 am

  6. I will prefer to post-back on the search.

    Comment by Nkonye Oyewusi — March 5, 2009 @ 7:26 am

RSS feed for comments on this post. TrackBack URL

Sorry, the comment form is closed at this time.