AJAX, JQuery, Drupal and Autocomplete

The combination of JQuery and Drupal makes it super easy to create AJAX-enabled websites. Drupal has auto-complete ability already built in, leaving only the actual data searching up to you to implement. Other AJAX functionality has been made a piece of cake to implement.

Here's how to build a form that asks the user for a node title (which it auto-completes) and fetches the node and displays it below the form, without reloading the page.

First the info file of the module we're going to call ajax_demo:

name = AJAX demo
description = Demonstrates the use of AJAX requests and Drupal autocomplete
package = Demo
version = "6.x-0.0"
core = 6.x

Then the module code explained:

<?php



/* ---- System hooks ---- */



function ajax_demo_menu(){

  return array(

    /*
      First register the menu path to our form,
      and tell Drupal what to do when we visit the path:
    */
    'demo' => array(
      /* Anybody should be able to access this URL: */
      'access arguments' => array('access content'),
      /* Tell Drupal to render a form: */
      'page callback' => 'drupal_get_form',
      /* Which form to render: */
      'page arguments' => array('ajax_demo_form'),
      'title' => 'Ajax demo',
      /*
         This is a normal item that should be
         displayed within the navigation menu:
      */
      'type' => MENU_NORMAL_ITEM,        ),

    /*
      Then we let Drupal know what to do when
      our auto-complete element asks for data:
    */
    'ajax/get-node-titles' => array(
      /* Anybody should be able to access this URL: */
      'access arguments' => array('access content'),
      /* The function to execute when this path is requested: */
      'page callback' => 'ajax_demo_get_node_titles',
      /*
         This is a utility URL used by our site,
         and should not be displayed anywhere in the menu system:
      */
      'type' => MENU_CALLBACK,
    ),

    /*
      We register a path where our nifty
      form can retrieve node data from:
    */
    'ajax/getdata' => array(
      /* Anybody should be able to access this URL: */
      'access arguments' => array('access content'),
      /* Which function should respond to this path: */
      'page callback' => 'ajax_demo_get_data',
      /*
         This is a utility URL used by our site,
         and should not be displayed anywhere in the menu system:
      */
      'type' => MENU_CALLBACK,
    ),

  );

}



/* ---- Forms ---- */



/*
  The function that tells drupal what our form should contain:
*/
function ajax_demo_form(){

  /*
    Add the Javascript/JQuery to handle the
    node fetching when the button is clicked:
  */
  drupal_add_js(drupal_get_path('module', 'ajax_demo') . '/ajax-demo.js');

  return array(

    'node-autocomplete' => array(
      /*
        Tell Drupal that this is an autocomplete field,
        and where to fetch auto-complete suggestions from:
      */
      '#autocomplete_path' => 'ajax/get-node-titles',
      /*
        Note that autyocomplete_path attribute  is the only difference
        between normal textfield and auto-complete field definitions.
      */
      '#title' => t('Type part of a node title'),
      '#type' => 'textfield',
    ),

    /* The button to trigger fetching of node data: */
    'get-node' => array(
      '#value' => t('Click to fetch the node'),
      '#type' => 'button',
    ),

    /* Add an empty div at the end of the form to hold fetched nodes: */
    array(
      '#value' => '<div id="node-area"></div>',
    ),

  );

}



/* ---- Callbacks ---- */



/*
  Fetch and return suggestions to the node title auto-complete:
  (Because we mapped ajax/get-node-titles to this function,
   any additional 'path elements' will be passed as variables
   to the function. eg.
     ajax/get-node-titles/bla
   will cause the value of $part to be 'bla'
  )
*/
function ajax_demo_get_node_titles($part){

  $results = array();
  $rows = db_query("SELECT title FROM {node} WHERE title LIKE('%%%s%');", $part);
  /*
    This'll fetch node titles that contain the user typed text
    We can show only titles that start with the text by changing:
    LIKE('%%%s%')
    to:
    LIKE('%s%')
  */

  while ($row = db_fetch_array($rows)){
    $results[$row['title']] = $row['title'];
  }
  /* The values of this array will be displayed to the user,
     while the keys will be used to replace what the user typed
     on selection.
  */

  /* Format the response to be acceptible to javascript */
  drupal_json($results);
}



/* Fetch and return the rendered node: */
function ajax_demo_get_data($title){

  $nid = db_result(db_query("SELECT nid FROM {node} WHERE title='%s'", $title));

  if ($nid){
    // Load and render the node:
    $node = node_load($nid);
    // print the rendered output as is to the response:
    print node_view($node);
  } else {
    print t('No node with that title could be found!');
  }

}

AttachmentSize
ajax_demo.zip1.6 KB