Damien Chatry

I write about stuff like web development, Drupal, python, design, etc.

07 Aug 2015

Trigger custom event on autocomplete suggestion selected in Drupal

After failing to configure Conditional Fields to show fields depending on whether or not a nodereference autocomplete field was filled, I came to the conclusion that it would be easier to code a custom behavior by overriding Drupal’s default autocomplete methods.

(function ($) {
  if (Drupal.jsAC) {
    // Override autocomplete method and add trigger
    // to retrieve the selected node.
    Drupal.jsAC.prototype.hidePopup = function (keycode) {
      // Select item if the right key or mousebutton was pressed.
      if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
        this.select(this.selected);
      }
      // Hide popup.
      var popup = this.popup;
      if (popup) {
        this.popup = null;
        $(popup).fadeOut('fast', function () { $(popup).remove(); });
      }
      this.selected = false;
      $(this.ariaLive).empty();
    };
  }

  $(document).ready(function() {
    $('#autocomplete-field').bind('autocompleteSelect', function(event, node) {
      alert(node.autocompleteValue);
    });
  });
})(jQuery);

Now with a practical use case, let’s say we want to show or hide a field depending on nodereference autocomplete field. But we don’t want the field to show if the content of the autocomplete field is not valid (it should contain the node title and the nid between brackets, just like this: TITLE [nid:NID].

(function ($) {
  if (Drupal.jsAC) {
    // Override autocomplete method and add trigger
    // to retrieve the selected node.
    Drupal.jsAC.prototype.hidePopup = function (keycode) {
      // Select item if the right key or mousebutton was pressed.
      if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
        this.select(this.selected);
      }
      // Hide popup.
      var popup = this.popup;
      if (popup) {
        this.popup = null;
        $(popup).fadeOut('fast', function () { $(popup).remove(); });
      }
      this.selected = false;
      $(this.ariaLive).empty();
    };
  }

  $(document).ready(function() {
    // Default to hidden.
    toggleField(false);
    
    $('#autocomplete-field').keyup(function(event) {
        // Check if node is specified in field.
        var state = isValidNode($(this).val());
        toggleField(state);
    });

    $('#autocomplete-field').bind('autocompleteSelect', function(event, node) {
      if (node.autocompleteValue !== '') {
        toggleField(true);
      }
    });

    // Check if node is specified in field.
    function isValidNode(inputText) {
      var pattern = new RegExp(/.*\[nid:[0-9]+\]/g);
      return pattern.test(inputText);
    };

    // Show/Hide other field according to autocomplete
    // field value.
    function toggleField(state) {
      if (state === false) {
        $('#conditional-field').hide();
      } else {
        $('#conditional-field').show();
      }
    }
  });
})(jQuery);

Note: if you’re using Drupal 6, use this code instead:

<pre><code>(function ($) {
  if (Drupal.jsAC) {
    // Override autocomplete method and add trigger
    // to retrieve the selected node.
    Drupal.jsAC.prototype.hidePopup = function (keycode) {
      // Select item if the right key or mousebutton was pressed.
      if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
        this.input.value = $(this.selected).context.autocompleteValue;
        $(this.input).trigger('autocompleteSelect', $(this.selected));
      }
      // Hide popup
      var popup = this.popup;
      if (popup) {
        this.popup = null;
        $(popup).fadeOut('fast', function() { $(popup).remove(); });
      }
      this.selected = false;
    };
  }

  $(document).ready(function() {
    $('#autocomplete-field').bind('autocompleteSelect', function(event, node) {
      alert(node.autocompleteValue);
    });
  });
})(jQuery);