2

I have a textfield autocomplete field that shows a list of full user names and email addresses as designed but when a user is selected, the user id is displayed in the field; not the name and email address. This is the form element:

$form['people'] = [
  '#type' => 'textfield',
  '#placeholder' => t('Search by name'),
  '#autocomplete_route_name' => 'my_module.people',
];

This is the autocomplete handler in the controller:

public function handleAutocomplete(Request $request) {

  $query = $this->database->select('simplenews_subscriber', 'ss');
  $or = $query->orConditionGroup()
    ->condition('pa.address_given_name', '%' .$request->query->get('q') . '%', 'LIKE')
    ->condition('pa.address_family_name', '%' .$request->query->get('q') . '%', 'LIKE');
  $query->leftJoin('simplenews_subscriber__subscriptions', 'sss', 'sss.entity_id = ss.id');
  $query->leftJoin('profile', 'p', 'p.uid = ss.uid');
  $query->leftJoin('profile__address', 'pa', 'pa.entity_id = p.profile_id');
  $query->fields('ss', ['uid', 'mail']);
  $query->fields('pa', ['address_given_name', 'address_family_name']);
  $query->condition($or);
  $query->orderBy('address_given_name');
  $query->range(0, 10);

  $results = $query->execute()->fetchAll();

  $users = [];

  foreach ($results as $user) {
    $users[] = [
      'value' => $user->uid,
      'label' => $user->address_given_name . ' ' . $user->address_family_name . ' (' . $user->mail . ')',
    ];
  }

  return new JsonResponse($users);
}

The autocomplete textfield populates properly. I just want the first name, last name and email address to show after a selection has been made.

3

1 Answer 1

0

To get this working I had to create a hidden field to store the value and use a custom selectHandler applied via class.

JavaScript File

(function ($, Drupal) {

  'use strict';

  /**
   * Override drupal selectHandler function
   */
  function customSelectHandler(event, ui) {
    var valueField = $(event.target);
    if($(event.target).hasClass('MYCUSTOM-autocomplete')) {
      var valueFieldName = event.target.name+'_value';
      if($('input[name='+valueFieldName+']').length > 0) {
        valueField = $('input[name='+valueFieldName+']');
        // update the labels too
        const labels = Drupal.autocomplete.splitValues(event.target.value);
        labels.pop();
        labels.push(ui.item.label);
        event.target.value = labels.join(', ');
      }
    }
    const terms = Drupal.autocomplete.splitValues(valueField.val());
    // Remove the current input.
    terms.pop();
    // Add the selected item.
    terms.push(ui.item.value);

    valueField.val(terms.join(', '));
    // Return false to tell jQuery UI that we've filled in the value already.
    return false;
  }

  Drupal.behaviors.myCustomAutocomplete = {
    attach: function(context, settings) {
      // attach custom select handler to fields with class
      $('input.MYCUSTOM-autocomplete').autocomplete({
        select: customSelectHandler,
      });
    }
  };

})(jQuery, Drupal);

Form PHP

$form['my_field'] = array(
  '#type' => 'textfield',
  '#attributes' => ['class' => ['MYCUSTOM-autocomplete'],],
  '#autocomplete_route_name' => 'mymodule.myfield_autocomplete',
);
// field value
$form['my_field_value'] = array(
  '#type' => 'hidden',
);

On our forms we also have an AJAX callback on the autocompleteselect event, and I've noticed the value for the hidden field is blank but the userInput on the $form_state has the value.

Problem with this is the splitValues function may not work well for the labels, since it appears to be comma-delimited. You may want to write your own to handle it. It also won't work well if using the same form twice on a page, but there may be a way to narrow down the selector on the hidden field.

Your Answer

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

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