1

I have created a custom module called trim_users. What the module does is to alter the (menu) page callback of the user references module to execute a modified (by me) function of the user references module. The modification I've made is simple: I've altered a database query so that the users returned into my forms' autocomplete field is a trimmed down list of my users. I've joined on a 'user.team' field and I'm saying give me all the users where the team is 'x' and 'y'. So first the user enters the two teams into my form: team 'x' and 'y'. Then the user goes to enter a user. After the first character is input I want my trimmed list of users to drop-down in the autocomplete field.

I'm stuck on one bit: how do I send the values of team 'x' and 'y' sitting in my (as of yet unsubmitted) form so that the database query, in my trim_users module, can populate the condition clause with these two values?

Do I need to add an AJAX property to my form elements: 'enter team 1' and 'enter team 2' so that on change a function is called and the entered values made available to my trim_users module?

Thanks. Hope I explained that okay.

1 Answer 1

0

First, you shouldn't have to modify the page callback from the user references module. Instead, use hook_form_alter() (or hook_form_FORM_ID_alter()) to change the #autocomlete_path attribute of the user reference text box to point to you're callback instead. That way you aren't modifying the module's stuff and you have the option of using the default implementation somewhere else. This is generally a better option than modifying another module's menu items.

For your particular use case, you'll do what you actually suggested; use the AJAX properties on the team fields to make the information available to the autocomplete callback. In practice it's slightly more complex than that, but you've already got the right idea. There's an article on Active LAMP that does pretty much the same thing.

First let's see about your custom autocomplete callback. You need to know which teams (Team X and Team Y as you put it) to filter by and what string to search for. In the following code, you first create a menu item for your callback, then define the actual autocomplete callback. The menu item uses two wild cards in the path to provide the ids for Team X and Team Y to the callback. You do not need to specify a wildcard for the search string, Drupal will handle that for you. In your callback, use the id information to narrow your user query results.

function trim_users_menu() {
  $item['trim-users/autocomplete/%/%'] = array(
    'page callback' => 'trim_users_autocomplete_callback',
    'page arguments' => array(2, 3),
    'type' => MENU_CALLBACK,
  );
  return $item;
}

function trim_users_autocomplete_callback($x, $y, $string) {
  // Here, use the query you altered for finding the correct users.
  $query = <youre altered query>;
  // Now, return the available User options.
  // Taken from user_reference_autocomlete, minus the hyperlink removal.
  $matches = array();
  foreach ($query->fetchAll() as $row) {
    $matches[$row['title'] . " [uid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
  }

  // return for JS
  drupal_json_output($matches);
}

Now you need to alter the form to make the user reference field use this custom autocomplete callback. The url you use for the user reference field's #autocomplete_path will follow the pattern of the menu item you create. Suppose you want to filter the users to Team X, with id 1, and Team Y, with id 2. You're path will be trim-users/autocomplete/1/2. To get team ids for the path, you use #ajax['callback'] settings on the Team fields to respond to change events. For example, set the #ajax['callback'] property to trim_users_team_selected. When the Team field value changes, Drupal will rebuild the form then run your #ajax['callback'] to update the form on the client. So, inhook_form_alter()`, check if the team fields have a value, and if they do use it to build the autocomplete callback path you assign to the user reference field.

function trim_users_form_alter(&$form, &$form_state) {
  // Check if it's the correct form, or use hook_form_FORM_ID_alter instead.
  ...

  // Check the $form_state to see if there's a value for the Team fields
  if (isset($form_state['input']['field_name']['#value']) {
    // Get the value of the field and use it in the autocomplete callback path
    ...
  }
  ...
}

// Return the User Reference field element from the rebuilt form. This will
// replace the existing field element on the client.
function trim_users_team_selected($form, $form_state) {
  return $form['user_reference_field'];
}

There's a few other things you have to do, like set the #ajax['wrapper'] property, but that's all part of using #ajax['callback'] so I'm not going to get into that here. This should at least get you on your way, you just need to figure out the specifics of retrieving and setting the form field values.

8
  • Thanks @Chaulky. I'm with you up to the second sentence in your third paragraph - then I get lost. I don't get: 'In these callbacks, modify the #autocomplete_path on the reference field to include the selected team in the url.' and 'Then you would make the #autocomplete_path attribute trim-users/autocomplete/x/y.'
    – dbj44
    Commented Jun 5, 2013 at 15:43
  • I updated the answer with more code and better explanations. Let me know if it's still not clear.
    – Chaulky
    Commented Jun 5, 2013 at 20:47
  • I've tried to follow your suggestions. I have posted my code in my question. It works apart from one thing. I cannot pass $teams to the function _trim_users_potential_references_standard. One solution is to use variable_set and variable_get, but that feels like a horrible hack.
    – dbj44
    Commented Jun 6, 2013 at 13:03
  • You're missing the point of the #ajax['callback'] function. Notice in my example that the trim_users_team_selected() returns a form element, not Team ids. I suggest you read more about using #ajax['callback'] from the Form API documentation (see link in my answer). Also, you pass the team ids as new path wildcards for your custom autocomplete function. Then, when your autocomplete function is called, it will be passed the team ids. Your menu callback path should be trim-users/autocomplete/%/%/%/%/%, the last two should be the team ids.
    – Chaulky
    Commented Jun 6, 2013 at 19:35
  • Okay. I'll rethink.
    – dbj44
    Commented Jun 6, 2013 at 20:13

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.