2

I have a form that is using #autocomplete_path on a textfield. In general it works fine.

Is there a way to have the autocomplete callback not fire until a minimum number of characters have been entered?

Is the only real option to override Drupal.ACDB.prototype.search with my own version, or is there a clean way to do this?

I am not interested in server side solutions to limit the result set; I am trying to decrease server load here and really need a client-side solution to prevent useless requests from ever being generated.

3 Answers 3

3

Here's two approaches:

  1. Replace the entire autocomplete.js with your customized version

    /**
     * Implements hook_js_alter
     * Replace autocomplete.js with customized version
     */
    function MY_MODULE_js_alter(&$javascript) { 
      $javascript['misc/autocomplete.js']['data'] = drupal_get_path('module', 'MY_MODULE') . '/js/autocomplete.js';
    }
    
  2. Override Drupal.ACDB.prototype.search with a custom version

Copy to theme script.js or module js file, as long as it's added after /misc/autocomplete.js it will override it.

(function($) {

/**
 * Performs a cached and delayed search.
 *
 * Override adds minimum text string length for lookup.
 * See /misc/autocomplete.js for original function.
 */
Drupal.ACDB.prototype.search = function (searchString) {

  // Minimum search string length
  var min = 3; 
  var db = this;
  this.searchString = searchString;

  // See if this string needs to be searched for anyway.
  searchString = searchString.replace(/^\s+|\s+$/, '');
  if (searchString.length <= min ||
    searchString.charAt(searchString.length - 1) == ',') {
    return;
  }

  // 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. We use Drupal.encodePath instead of
    // encodeURIComponent to allow autocomplete search terms to contain slashes.
    $.ajax({
      type: 'GET',
      url: db.uri + '/' + Drupal.encodePath(searchString),
      dataType: 'json',
      success: function (matches) {
        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(Drupal.ajaxError(xmlhttp, db.uri));
      }
    });
  }, this.delay);
};
})(jQuery);
6
  • Number two is almost exactly what I am doing. I did have to wrap it in a closure, though, to avoid "$ is undefined" errors. It just makes me feel dirty...
    – mpdonadio
    Jul 8, 2013 at 22:30
  • Yes, I think it's sometimes referred to as Monkey Patching :) P.S jQuery namespace wrapper added to answer there. Jul 8, 2013 at 22:34
  • @MPD , sorry I'm not understand, where to add the "Drupal.ACDB.prototype.search = function" function, will i replace it in autocomplete.js file itself.
    – Bala
    Oct 9, 2013 at 8:27
  • @Bala You don't edit the core misc/autocomplete.js You can put this in your our JS file that gets included in a module or a theme. When your gets loaded, it will override the core declaration.
    – mpdonadio
    Oct 9, 2013 at 13:05
  • @MPD I put the autocomplete.js inside the custom module and I want to know where to add the 2 step ?
    – Bala
    Oct 9, 2013 at 13:12
2

I am not suggesting that you should just go and edit this directly, but, the behavior is dictated by just having any characters entered into the input field.

Thus, you could change

if (input.value.length > 0)

to

if (input.value.length > WHATEVERVALUE)

around line 94 in misc/autocomplete.js, and, for D7, you could change

if (input.value.length > 0 && !input.readOnly) {

around line 102 similarly.

Of course, this will be creating a site wide behavior change (and hacked core) so maybe/hopefully there is a way to include a different autocomplete.js in for your specific form/form element (overriding theme_textfield() might work).

2
  • 1
    It's also possible to override just the Drupal.ACDB.prototype.search function in another js file, as MPD referred to in the question, which removes the need to alter the core file. Alternatively, hook_js_alter could be used to swap out autocomplete.js with a new file. Jul 8, 2013 at 22:11
  • indeed, hence my last paragraph
    – Jimajamma
    Jul 8, 2013 at 22:34
1

I'm not aware of a clean way to do this persay besides overriding. D8 mostly re-wrote most of the autocomplete ajax because its a rather limited library in D7.

That being said if you dont want to override stuff you can always use the bundled jQuery and its auto-complete functions to do the same thing -- it doesnt end up being that much code. Here is an example from a Russian blog for jquery autocomplete in Drupal 7 with a live example on the page which I have adopted on 1 of my own projects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.