开发者

Drupal autocomplete, callback with multiple parameters

开发者 https://www.devze.com 2023-03-21 19:28 出处:网络
I am adding some autocomplete on a form alter. The problem is that in the callback, only the string in the textfield The autocomplete is on, is available. I also want to access a value from another te

I am adding some autocomplete on a form alter. The problem is that in the callback, only the string in the textfield The autocomplete is on, is available. I also want to access a value from another textfield in the callback. How is this possible ?

/**
 * Implements hook_form_alter().
 */
function webform_conversion_jquery_form_webform_client_form_1_alter(&$form, &$form_state, $form_id) {
          //Load some extra function to process data
        module_load_include('inc', 'webform_conversion_jquery', '/includes/dataqueries');

        //Add extra js files
        drupal_add_js(drupal_get_path('module', 'webform_conversion_jquery') . '/js/conversionform.js');
        $form['submitted']['correspondentadress']['cor_street']['#autocomplete_path'] = 'conversionform/conversion_street';
    }
}

/**
 * Implements hook_menu().
 */
function webform_conversion_jquery_menu() {
    $items = array();


    $items['conversionform/conversion_street'] = array(
        'title' => 'Conversion street autocomplete',
        'page callback' => 'conversion_street_开发者_如何学Cautocomplete',
        'access callback' => 'user_access',
        'access arguments' => array('access content'),
        'type' => MENU_CALLBACK,
    );

    return $items;
}

/**
 * Retrieve a JSON object containing autocomplete suggestions for streets depending on the zipcode.
 */
function conversion_street_autocomplete($street = '') {
    $street = "%" . $street . "%";
    $matches = array();
    $result = db_select('conversion_adresslist')
                    ->fields('conversion_adresslist', array('street'))
                    ->condition('street', $street, 'like')
                    ->execute();
    foreach ($result as $street) {
        $matches[$street->street] = $street->street;
    }
    drupal_json_output($matches);
}

I just want to be able to post extra information in the function:

conversion_street_autocomplete($street = '', $extraparameter)


I had the same problem and have figured out a way, which is not too strenuous. It involves overriding the textfield theme and then passing your parameter to the theme function.

First create declare your theme function:

function mymodule_theme() {
  $theme_hooks = array(
    'my_module_autocomplete' => array(
      'render element' => 'element',
    ),
  );
  return $theme_hooks;
}

Next we need to add the theme and the variable to our form element. In my case, the form element is part of a field widget:

 function my_module_field_widget_form($form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {

  if($instance['widget']['type'] == 'my_module_field_type') {

    $element['my_module_field'] = array(
      '#type' => 'textfield',
      '#autocomplete_path' => 'my-module/autocomplete',
      // THIS IS THE IMPORTANT PART - ADD THE THEME AND THE VARIABLE.
      '#theme' => 'my_module_autocomplete',
      '#my_module_variable' => $field['field_name'],
    );
  }
  return $element;
}

Then implement the theme function. This is a copy of theme_textfield from includes/form.inc with one important difference - we append the variable to the autocomplete path:

function theme_my_module_autocomplet($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'text';
  element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength'));
  _form_set_class($element, array('form-text'));

  $extra = '';
  if ($element['#autocomplete_path'] &&     drupal_valid_path($element['#autocomplete_path'])) {
    drupal_add_library('system', 'drupal.autocomplete');
    $element['#attributes']['class'][] = 'form-autocomplete';

    $attributes = array();
    $attributes['type'] = 'hidden';
    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
    // THIS IS THE IMPORTANT PART. APPEND YOUR VARIABLE TO THE AUTOCOMPLETE PATH.
    $attributes['value'] = url($element['#autocomplete_path'] . '/' . $element['#my_module_variable'], array('absolute' => TRUE));
    $attributes['disabled'] = 'disabled';
    $attributes['class'][] = 'autocomplete';
    $extra = '<input' . drupal_attributes($attributes) . ' />';
  }

  $output = '<input' . drupal_attributes($element['#attributes']) . ' />';

  return $output . $extra;
}

Now the variable will be available as the first parameter on the autocomplete callback function:

function _my_module_autocomplete($my_module_variable, $search_string) {
  // Happy days, we now have access to our parameter.
}


Just in case anyone is still having trouble with this I found a great solution while trying to figure out how to do this. I had a year select list and that dictated what data was displayed in the autocomplete field. The solution basically has an ajax callback function for the select list that can then update the autocomplete field with an extra parameter in the url. Anyways, it is really well explained in the following article.

http://complexdan.com/passing-custom-arguments-drupal-7-autocomplete/

*A note of caution, I was going crazy trying to figure out why it did not work and it turns out you can't have the same form on the page twice (I needed to because I was displaying it differently for mobile devices) because you are using an id for the ajax callback. I added an extra argument to accomplish that. It is called uniqueid in the below example.

function report_cards_comparison_form($form, &$form_state, $uniqueid) {

   $curryear = t('2012');

   $form['year_select'] = array(
        '#title' => t('School Year'),
        '#type' => 'select',
        '#options' => array(
            '2012' => t('2012'),
            '2013' => t('2013'),
            '2014' => t('2014'),
            '2015' => t('2015'),
          ),
        '#default_value' => $curryear,
        '#ajax' => array(
          'callback' => 'report_cards_comparison_form_callback',
          'wrapper' => $uniqueid,
          'progress' => array(
                'message' => 'Updating Schools...',
                'type' => 'throbber'
            ),
        ),

  ); 

  $form['choice'] = array(
    //'#title' => t('Search By:  School Name'),
    '#type' => 'textfield',
    '#attributes' => array(
        'class' => array('school-choice'),
        'placeholder' => t('Start Typing School Name...'),
    ),
    '#required' => TRUE,
    '#autocomplete_path' => 'reportcards/autocomplete/' . $curryear,
    '#prefix' => '<div id="' . $uniqueid . '">',
    '#suffix' => '</div>',
  ); 

  $form['submit'] = array(
    '#type' => 'submit',
    '#prefix' => '<div class="submit-btn-wrap">',
    '#suffix' => '</div>',
    '#value' => t('Search'),
    '#attributes' => array('id' => 'add-school-submit'),
  );

  return $form;
}

/**
 * Ajax Callback that updates the autocomplete ajax when there is a change in the Year Select List
 */
function report_cards_comparison_form_callback($form, &$form_state) {
  unset($form_state['input']['choice'], $form_state['values']['choice']);
  $curryear = $form_state['values']['year_select'];

  $form_state['input']['choice'] = '';
  $form['choice']['#value'] = '';
  $form['choice']['#autocomplete_path'] = 'reportcards/autocomplete/' . $curryear;

  return form_builder($form['#id'], $form['choice'], $form_state);
}

and I can call the form by doing this...

print render(drupal_get_form('report_cards_comparison_form', 'desktop-schoolmatches'));


You can do it by overriding methods from autocomplete.js in your own js. Here is example:

(function($) {
  Drupal.behaviors.someModuleOverrideAC = {
    attach: function(context, settings) {
      // Next is copied and adjusted method from autocomplete.js
      Drupal.jsAC.prototype.populatePopup = function() {
        var $input = $(this.input);
        var position = $input.position();
        // Show popup.
        if (this.popup) {
          $(this.popup).remove();
        }
        this.selected = false;
        this.popup = $('<div id="autocomplete"></div>')[0];
        this.popup.owner = this;
        $(this.popup).css({
          top: parseInt(position.top + this.input.offsetHeight, 10) + 'px',
          left: parseInt(position.left, 10) + 'px',
          width: $input.innerWidth() + 'px',
          display: 'none'
        });
        $input.before(this.popup);

        // Do search.
        this.db.owner = this;

        if ($input.attr('name') === 'field_appartment_complex') {
          // Overriden search
          // Build custom search string for apartments autocomplete
          var $wrapper = $('div.apartments-autocomplete');
          var $elements = $('input, select', $wrapper);
          var searchElements = {string: this.input.value};
          $elements.each(function() {
            searchElements[$(this).data('address-part')] = $(this).val();
          });
          var string = encodeURIComponent(JSON.stringify(searchElements));
          this.db.search(string);
        }
        else {
          // Default search
          this.db.search(this.input.value);
        }
      };
    }
  };
}(jQuery));

In your server callback:

function some_module_autocomplete_ajax($string) {
  // Decode custom string obtained using overriden autocomplete js.
  $components = drupal_json_decode(rawurldecode($string));
  // Do you search here using multiple params from $components
}


Ok, for as far as I can see it is not possible. maybe you can roll your own with the ajax functionality in fapi http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7#ajax

For now I solved it by implementing jquery.ui.autocomplete which is included in drupal 7

0

精彩评论

暂无评论...
验证码 换一张
取 消