Changing Drupal's autocomplete path with JavaScript

Posted on July 17, 2012, 10:54 p.m.

Ever had an interface that needed an autocomplete field? Happens all the time - and Drupal makes that task trivial. But what if you need to change the autocomplete URL without reloading the page? Use these steps, and you'll find out how to do so with JavaScript.

For the purposes of this tutorial, we'll assume you don't care too much about the initial URL. So let's make it obvious that it's a placeholder. Let's start by declaring our menu entries.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php      
function our_autocompleted_field_menu() {                                     
  $items = array();                                                           
  $items['our_autocompleted_field_form'] = array(                             
    'type' => MENU_CALLBACK,                                                  
    'access callback' => TRUE,                                                
    'page callback' => 'drupal_get_form',                                     
    'page arguments' => array('our_autocompleted_field_form'),                
  );                                                                          
  $items['our_autocompleted_field/autocomplete/%'] = array(                   
    'type' => MENU_CALLBACK,                                                  
    'access callback' => TRUE,                                                
    'page callback' => 'our_autocompleted_field_autocomplete',                
    'page arguments' => array(2),                                             
  );                                                                          
  return $items;                                                              
}

Now let's declare the form with our field. Like any other autocomplete field, we declare it by using the #autocomplete property on our form definition.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php                                                                               
function our_autocompleted_field_form() {                                     
  $form = array();                                                            
  $form['our_autocompleted_field_toggle'] = array(                                   
    // This is just a sample link to demonstrate the dynamic autocomplete URL.
    '#type' => 'markup',                                                      
    '#value' => '<a id="our-autocompleted-field-toggle" href="#">Toggle</a>', 
  );                                                                          
  $form['our_autocompleted_field'] = array(                                   
    '#type' => 'textfield',                                                   
    '#id' => 'our-autocompleted-field',                                       
    // Drupal needs a valid autocomplete path, otherwise it will not add the  
    // behavior. So we add the placeholder argument and replace that on the   
    // JS frontend.                                                           
    '#autocomplete_path' => 'our_autocompleted_field/autocomplete/PLACEHOLDER',
  );                                                                          
  return $form;                                                               
}

Now, let's define our autocomplete function. To demonstrate the dynamic capabilities, let's use the first argument - which comes along with the path - as a way to tell us whether to return results in lowercase or uppercase. Of course, you can use the dynamically-changed URL to vary your results however you want.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php      
function our_autocompleted_field_autocomplete($letter_case, $input) {         
  if ($letter_case == 'uppercase') {                                          
    $function = 'strtoupper';                                                 
  }                                                                           
  else {                                                                      
    $function = 'strtolower';                                                 
  }

  $matches = array(                                                           
    'Suggestion 1',                                                           
    'Suggestion 2',                                                           
  );                                                                          
  $matches = array_map($function, $matches);

  print json_encode($matches);                                                
  exit();                                                                     
}

Finally, we use a little bit of magic on the frontend to change the autocomplete path. The trick is to reload the autocomplete object that Drupal generates, otherwise, the change won't take effect. You also need to get rid of the old behavior - that way you avoid confusing duplicate calls. Find or create your module's JavaScript file. Then add the following code:

 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
$(document).ready(function() {                                                
  // ID format is {OUR-FIELD-ID}-autocomplete.                                  
  var autocompletePath = $('#our-autocompleted-field-autocomplete')           
                         .val().replace('/PLACEHOLDER', '');

  // Keep track of the case we're in.                                         
  var isUpperCase = false;

  $('#our-autocompleted-field-toggle').click(function() {                     
    if (isUpperCase) {                                                        
      var newURL = autocompletePath + '/lowercase';                           
      isUpperCase = false;                                                    
    }                                                                         
    else {                                                                    
      var newURL = autocompletePath + '/uppercase';                           
      isUpperCase = true;                                                     
    }                                                                         
    // Trick Drupal into rebinding the autocomplete behavior.                 
    $('#our-autocompleted-field-autocomplete').val(newURL)                    
    .removeClass('autocomplete-processed');

    $('#our-autocompleted-field').unbind().val('');                           
    Drupal.behaviors.autocomplete(document);

    return false;                                                             
  });

  // Simulate a click when initializing so that we have a valid autocomplete  
  // path.                                                                    
  $('#our-autocompleted-field-toggle').click();                               
});

And that's it. This code will toggle your autocomplete results between uppercase and lowercase. It's a contrived example, of course. But think of the possibilities!

Learning Drupal? Subscribe to my Drupal articles, tips and tutorials.