Autocomplete with dynamic arguments?

thorie - July 9, 2008 - 09:25

I'm trying to use the (nifty) autocomplete feature, but I've run into a problem: I need to send an extra parameter to the callback (I assume by tacking it onto the Drupal path) , but this parameter changes depending on the user's selection in a drop-down in the same form. Is there a way of modifying #autocomplete_path, i.e. the URI in the JS object, dynamically in reponse to user selection.

To elaborate: I have a country name dropdown on the form. Whenever the user selects a different country from that dropdown, I need to limit the searches performed in the autocomplete callback, i.e. I need to send the current country selection in as a parameter to the callback so that I only get results that are relevant to the currently selected country.

Any ideas on how to accomplish this?

The thing you need to do is

Iumentum - July 9, 2008 - 11:49

The thing you need to do is to process the autocomplete again in the javascript when changing country.
I made a little script for that a while back for a colleage, hope it will do the trick for you.

First we change the value of the hidden field related to the autocomplete field to the new path you want to send your http request to
$('#edit-name-autocomplete').val('test');
Then you have to unbind following so they wont double trigger when we attach the behavior again
$("#edit-name").unbind('keydown');
$("#edit-name").unbind('keyup');
$("#edit-name").unbind('blur');

Then we remove the class 'autocomplete-processed' from the hidden field as well.
When drupal attach the autocomplete behavior it checks for this class to see if the behavior is already set.
$('#edit-name-autocomplete').removeClass('autocomplete-processed');

Then we tell drupal to set the behavoirs again.
Drupal.attachBehaviors(document);

This seemed to work as the solution for what my colleage needed but i havent fully tested the solution myself.

Thanks guys, this is

thorie - July 9, 2008 - 22:25

Thanks guys, this is awesome!

I ended up implementing a tweaked version of Iumentum's code, because that was easy to do and served my purposes. I do think that a more comprehensive solution like the one provided by j_ten_man should go in core, though. Like right now ;)

Anyway, thanks again for prompt and sound solutions!

I overwrote the standard

j_ten_man - July 9, 2008 - 12:58

I overwrote the standard autocomplete functionality as follows

if(Drupal.jsEnabled){
$(document).ready(function(){
//Replace the autocomplete functionality for this page so that we
//are able to dynamically use two fields to return results.
//Copied from misc/autcomplete.js
if (Drupal.ACDB) {
Drupal.ACDB.prototype.search = function (searchString) {
  var db = this;
  //Normally searchstring is just searchString. Add any additional fields
  //on the search string.  Custom changes
  this.searchString = $('#edit-name').val() + "/" +searchString;
  searchString = $('#edit-name').val() + "/" +searchString;

  // See if this key has been searched for before
  if (this.cache[searchString]) {
    return this.owner.found(this.cache[searchString]);
  }

  // Initiate delayed search
  if (this.timer) {
    clearTimeout(this.timer);
  }
  this.timer = setTimeout(function() {
    db.owner.setStatus('begin');

    // Ajax GET request for autocompletion
    $.ajax({
      type: "GET",
      url: db.uri +'/'+ Drupal.encodeURIComponent(searchString),
      success: function (data) {
        // Parse back result
        var matches = Drupal.parseJson(data);
        if (typeof matches['status'] == 'undefined' || matches['status'] != 0) {
          db.cache[searchString] = matches;
          // Verify if these are still the matches the user wants to see
          if (db.searchString == searchString) {
            db.owner.found(matches);
          }
          db.owner.setStatus('found');
        }
      },
      error: function (xmlhttp) {
        alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ db.uri);
      }
    });
  }, this.delay);
}
}
});
}

The handler for this looks like the following:

<?php
function module_autcomplete_custom_handler($string=""){
 
$matches = array();
 
$string = trim($string);
 
//Arg 3 is the dynamic field or $('#edit-name') from the jquery.
  //This value will change depending on your path. The path for this
  //call is a/b/c/#edit-name/search-string
 
$cat_1 = trim(arg(3));
 
/**
    Do query and save your matches.
  **/
 
print drupal_to_js($matches);
  exit();
}
?>

In my opinion its never a

Iumentum - July 9, 2008 - 13:46

In my opinion its never a good idea to overwrite anything in drupal's core so i will go far to try to find a workaround instead.
I find it important not to overwrite so you can easy update drupal to a never version without having to think of all the modifications made for the current system.
But sometimes you end up in situations where its the only solution :/ but as long as there is a workaround i find it wrong to overwrite anything outside the module its written for.
For that reason i made the above script instead of modifying/overwriting anything in drupal.
It took a little longer to figure out this method, but its easy to use and easy to implement in other modules/sites for future use.

Sorry I didn't explain

j_ten_man - July 9, 2008 - 15:08

Sorry I didn't explain myself. I didn't actually overwrite the code. I put it in my module in and loaded that javavscript only on the page that I needed it on. It would have been a really bad idea to actually overwrite the function in autocomplete.js. Thanks for making that clear for everyone.

Dependent autocomplete nodereference fields

mistresskim - September 2, 2008 - 15:03

I'm trying to do a similar thing with two dependent autocomplete nodereference fields as explained here but not sure how to proceed. j_ten_man, could your script also be employed in this case? Has anyone else found another method?

Not sure. Everything that I

j_ten_man - September 6, 2008 - 12:59

Not sure. Everything that I did was in Drupal 5. You can try doing what I did and report. Just include the script in a js file on the page you need it on and it should override the standard.

 
 

Drupal is a registered trademark of Dries Buytaert.