4

I have made textfield to be autocomplete field by using hook_form_alter.

mymoudle_form_alter(&$form, &$form_state, $form_id){
   $form['field_state']['und'][0]['value']['#autocomplete_path'] ='get-state-values';
}
    function mymoudle_drupal_menu() {
    $items = array();   

    $items['get-country-value'] = array(
            'title' => 'Country Value',
            'page callback' => '_get_country_value',
            //'page arguments'  => array(1),
            'access arguments' => array('access content'),
            'type' => MENU_CALLBACK,
    );
    $items['get-state-values'] = array(
            'page callback' => '_get_state_values',
            'access arguments' => array('access content'),
            'type' => MENU_CALLBACK
    );
    return $items;
}

function _get_state_values($string){
    $country =$_SESSION['country']; 
    if($country == 'India'){                
        $state = array('Tamilnadu' => 'Tamilnadu','Karanataka' => 'Karanataka');
    }
    else{
        $state = array('NewYork' => 'NewYork','Manahattan' => 'Manahattan');
    }   
    print drupal_json_output($state);exit;  
}
function _get_country_value(){
    $country = $_REQUEST['valueSelected'];  
    $_SESSION['country'] = $country;
    print drupal_json_output($country);exit;
}

If I select country as India and type in the state as 'n' it shows me in auto-complete as two states with n words like tamilnadu and karnataka which is correct(it runs ajax to fetch the values as shown in screenshot-1). enter image description here

The issue over here is if I again change the country to 'Us' and type same 'n' it shows same set of results and it doesn't run the ajax(as shown in screenshoot-2). Its showing from cache I think for previous results.

enter image description here

NOTE: I want an fix for the ajax caching issue.

I have attached the screenshot of what's happening .How to avoid this issue?.Any help will be much appreciated.Thanks in advance.

7
  • are the country and the states selects dependent on each other?how? what would you expect?
    – Pan Chrono
    Commented Feb 10, 2015 at 23:08
  • @PanChrono: Yes they are dependent country and states.If I select Us as country and try in state as 'U' it should list only US related states alone in autocomplete.
    – Ram
    Commented Feb 11, 2015 at 4:29
  • can you share the code for that dependency?
    – Pan Chrono
    Commented Feb 11, 2015 at 9:35
  • @PanChrono: I have shared the code.
    – Ram
    Commented Feb 11, 2015 at 9:50
  • @Ram: Have you tried this? drupal.org/node/2374709
    – pown
    Commented Feb 17, 2015 at 5:07

7 Answers 7

3
+50

Since, there is no proper way, I opted for hack (or work around) to get this working. As already mentioned by @Clive, removing/disabling caching mechanism would require more work. This solution just skips the caching part.

Step1: Copy the entire misc/autocomplete.js to your module js scripts directory.

Step2: Comment or remove the following line from the copied file

// See if this key has been searched for before.
  //if (this.cache[searchString]) {
      // We dont want some things to be cached
    //return this.owner.found(this.cache[searchString]);
  //}

Step3: Implement hook_js_alter to override it to specific pages you like.

/**
 * Implements hook_js_alter
 * @param array $javascript
 */
function MYMODULE_js_alter(&$javascript) {
  if (arg(0) == 'MYPAGE') {
    $javascript['misc/autocomplete.js']['data'] = drupal_get_path('module', 'MYMODULE') . '/js/autocomplete.js';
  } 
}
2
  • 1
    I was looking for some-other way to do it instead of hacking. Since I can't find any other solutions for it I am using this method.
    – Ram
    Commented Feb 23, 2015 at 10:12
  • 2
    Same here, works also in Drupal 8.3, just look for all the places where the autocomplete.cache is used and comment those out, also the path is 'core/misc/autocomplete.js'! (you have to add the core/ part).
    – Larzan
    Commented Aug 19, 2017 at 13:15
2

Static caching is built in so you'll need to override Drupal.ACDB.proptotype.search.

This is untested but should be near the mark:

Drupal.ACDB.prototype.search = function (searchString) {
  var db = this;
  this.searchString = searchString;

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

  // THIS IS THE BIT TO REMOVE
  // 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);
};

That will change the behaviour site wide (or for the entire context in which you include the above snippet). To override for certain URIs you'll probably need to get a bit cleverer and monkey patch a few more core JS methods.

Also note that this doesn't disable caching, it just stops cached results from being returned instead of making the ajax call each time. To properly remove caching would require a bit more work.

1
  • 1
    Nice workaround. This one will work, if the autocomplete.js is loaded before this script execution.
    – pown
    Commented Feb 18, 2015 at 4:42
2

The cache is saved in a property of ACDB object, unfortunately we can't access the instances of this object. However we can override the search function prototype object of Drupal.ACDB in order to delete this cache before every query.

Overriding Drupal.ACDB prototype will affect all autocompletes in Drupal, so you can minimize the impact (of not having cache) including your override javascript code only in specific pages. Also you can minimize the impact checking for the autocomplete ID or specific class or attribute since (inside the search function) you know which is the input in your DOM.

First you must backup the Drupal.ACDB.prototype.search function:

Drupal.ACDB.prototype.search_bkp = Drupal.ACDB.prototype.search;

Then you can override search function and apply your logic to erase the cache and then call search again.

Drupal.ACDB.prototype.search = 
    function (searchString) {  
        // your autocomplete element in DOM
        // use it like $(this.owner.input) to access jQuery functions
        console.log( 'AC =', this.owner.input ); 

        // Deleting the cache, apply your logic
        // ej. if ($(ac.owner.input).attr('id') === 'my-id-of-the-ac-input') {}
        this.cache = {};
        this.search_bkp(searchString); 
};

Finally, you can execute the code above "whenever you want" (after Drupal.ACDB definition)... you can even try it in the Chrome console.

Hope that helps.

3
  • This does not work for Drupal 8 anymore as ACDB has been removed: drupal.org/node/2202701
    – Larzan
    Commented Aug 19, 2017 at 12:36
  • 1
    This works well. For consistency with the default ACDB object, it may be better to set cache to an empty object instead of an empty array: this.cache = {}; Commented Sep 6, 2017 at 15:35
  • @DavidLanier you are right. I changed it. Commented Sep 6, 2017 at 15:46
0

I think your problem lies in how you are setting the session variable. Cache has nothing to do with it.

Drupal only needs to retrieve the values for the fields once to render the form on the server side. Your code doesn't throw any errors because the country field is rendered before the state field, so the state field uses the default country value (first item in the array) to perform its calculation.

You need some client-side code (JQuery) to refresh the state values via AJAX whenever the country value is changed.

Have a look at Tenken's answer to a very similar question.

I would also consider using a hierarchical taxonomy to store your values rather than hard-coding them as per this documentation page.

3
  • Thanks,but this is not what I am expecting,I dont want to use hierarchical taxonomy since I am not following hierarchical pattern each one is different terms.I want an fix for the ajax caching issue.
    – Ram
    Commented Feb 17, 2015 at 4:50
  • Then ignore the last sentence and read the rest of the answer. In particular, follow the link to Tenken's answer.
    – Darvanen
    Commented Feb 17, 2015 at 4:53
  • AS I mentioned in the question I am making a textfield to be autocomplete using #autocomplete_path. $form['field_state']['und'][0]['value']['#autocomplete_path'] ='get-state-values';I cant pass an argument, by default it takes autocomplete search text as an argument. So that links doesn't help.
    – Ram
    Commented Feb 17, 2015 at 5:38
0

I think it is a session issue and session value only reflect after reload the page.

1
  • 4
    Session isn't involved - there's a client-side cache of results based on the URL used to gather them, all handled in JS
    – Clive
    Commented Feb 18, 2015 at 11:31
0

I had a similar problem I created an entity reference field, and then I wanted to have custom autocomplete result list based on another field value (for example a select box). I managed to pass the select box value as filter parameter to the custom drupal autocomplete_path handler(at the backend). The problem if I searched for "a" and select "val1" from the select box I will get some result list,but if I changed the select box value to "val2" and type the same search character "a" I will get result list related to "val1". It will not send an ajax call again because it is cached. So after many days of search I found a solution that resolved my problem, and that is by overriding the "Drupal.ACDB.prototype.search" I found the solution here :https://knackforge.com/blog/sujith/ajax-autocomplete-customization-textfield-drupal
The solution suggested @Clive works fine,I tested and it works.

0

I wanted a less intrusive solution for a Drupal 9 instance, so instead of copying the entire autocomplete.js file as mentioned above, I just overwrite one of the methods on the Drupal.autocomplete object. Here's what worked for me:

  1. Create a behavior and attach it to your form/ page In your attach method, and within a 'once' block, overwrite the Drupal.autocomplete.options.source variable, set it to your own method: Drupal.autocomplete.options.source = myOwnSourceData;
  2. Grab the contents of the function sourceData found in the /core/misc/autocomplete.js file (or the es6 version) and add it to your custom method named above.
  3. Remove all references in that code to the cache variable (read and write)
  4. Change all references to the autocomplete variable to make it global, it needs to be Drupal.autocomplete

In this way we're only overriding one function within the autocomplete file and not the entire file.

I really hope future iterations of Drupal allow us to turn caching off as an option in future.

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.