Drupal Ajax Autocomplete Dependent Form Elements Using jQuery

Our Task

Recently I was asked how to create an auto-complete form element from a parent form selection choice using Ajax. Below is our initial form. In this form students select a Country in the world and then an Educational Program offered in that country populates the Program select list via Ajax. Students must select a valid country before they may select a program.

Untitled

After selecting a country, available programs become available.

eap-ajax

The Drupal Form API and Ajax API should be able to power this all natively — but I was under a time crunch and fell back to a pure jQuery solution (which is bundled with Drupal by default). So this solution is still “drupal core” based — at a later time I may provide an updated post using solely the FAPI and Ajax API.

Implementing our Solution using a custom module

In a custom module .info file I add my javascript file dependency. This is where I will place my jQuery code:

scripts[] = feedback2_ajax.js

Alternatively, You could add this via a form_alter() call instead and using #attached FAPI key to add this JS to 1 specific form of your drupal website and slightly decrease the total global number of asset files requested by a visitor. By inserting this scripts[] entry in your module file this file is always requested on every page of the website. But, this approach is simple.

Then my javascript file actually does 99% of all the work wiring this all together. This code performs the following tasks:

  • inactivates the Program field on page load
  • wires an onClick listener to the Countries field which populates Program values for the selected country via Ajax if the click value is for the none default select option.
  • activates the Program field if the above actions occur correctly.
jQuery(function($) {

  $('#edit-field-survey-program-und option:gt(0)').remove();
  $('#edit-field-survey-program-und').attr('disabled', 'disabled');

  $("#edit-field-survey-country-und").click(function() {
    var selected_country = $("#edit-field-survey-country-und").val();
    if (selected_country != '_none') {
      $.ajax({
        type:'GET',
        url: '/eap-ajax/eap-country-programs/' + selected_country,
        data: '',
          success:function(data){
          //console.log("got: ");
          //console.log(data);
          // Do actual work.
          $('#edit-field-survey-program-und option:gt(0)').remove();
          $.each(data, function(key, value) {
            $('#edit-field-survey-program-und').append(
              '<option value="' + key + '">' + value + '</option>'
            );
          });
          $('#edit-field-survey-program-und').removeAttr('disabled');
        }
      }); 
    }
  });
});

Then in my module code I have to define the functions to return the data for the Ajax request. This is done by supplying the menu route for the request and its callback function in Drupal.

The menu route is provided by implementing hook_menu in Drupal:

// Define custom ajax callback url.
function eap_student_feedback2_menu() {
  $items['eap-ajax/eap-country-programs/%'] = array(
    'page callback' => '_eap_student_feedback2_programs_json_endpoint',
    'page arguments' => array(2),
    'type' => MENU_CALLBACK,
    'access callback' => TRUE,
  );
  return $items;
}

As you can see it references a callback function,  _eap_student_feedback2_programs_json_endpoint, we must supply it as well:

function _eap_student_feedback2_programs_json_endpoint($country_term_id) {
  $matches = array();
  $result = db_query('
      SELECT tth.tid, ttd.name AS term_name
      FROM taxonomy_term_hierarchy tth
      LEFT JOIN taxonomy_term_data ttd ON tth.tid = ttd.tid
      WHERE tth.parent = :tid
      ORDER BY 2 ASC
  ', array(':tid' => $country_term_id));
  // add matches to $matches
  foreach ($result as $row) {
    $matches[$row->tid] = check_plain($row->term_name);
  }
  // return for JS
  return drupal_json_output($matches);
}

All these pieces working together allow our form to be more interactive by using Ajax. Currently this form doesn’t degrade well for non-javascript enabled devices; nor is it 100% using Drupal APIs. But, it is using libraries and code provided in any default installation of Drupal 7.

Looking for quality Drupal Web Hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , , , , , | Posted under Drupal | RSS 2.0

Author Spotlight

David Gurba

David Gurba

I am a web programmer currently employed at UCSB. I have been developing web applications professionally for 8+ years now. For the last 5 years I’ve been actively developing websites primarily in PHP using Drupal. I have experience using LAMP and developing data driven websites for clients in aviation, higher education and e-commerce. If you’d like to contact me I can be reached at david.gurba@arvixe.com

Leave a Reply

Your email address will not be published. Required fields are marked *


3 + 7 =

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>