3

Similar questions:

Ajax wrapper replacement on a field widget form

how to create an AJAX field widget

Problem:

Get FIELD_NAME and DELTA in AJAX callback function? (See below)

What is done:

Change value of a textfield in a widget form (see here) upon value change (jQuery event .change()) of another textfield in widget form.

Code Sample:

in hook_widget_form:

// Changes of this field fire the AJAX event
$element['value'] = ...
$element['value']['#ajax'] = array(
                    'callback' => 'some_ajax_callback',
                    'wrapper' => 'location-div',
                    'method' => 'replace',
                    'effect' => 'fade'
            );
// This field is updated upon AJAX call
$element['location'] = ...
// Here is where the actual change occurs
if(!empty($form_state['values'][$field['field_name']]['und'][$delta]['value'])) {
            $element['location']['#value'] = ...;
        }

in some_ajax_callback:

function some_ajax_callback ($form, $form_state) {
  // Where do I get FIELD_NAME, and DELTA?
  return $field[FIELD_NAME]['und'][DELTA]['location'];
}

What happens?

As it is mentioned here #default_value is not populated using AJAX so according to this #value should be used instead.

The problem is how to get FIELD_NAME and DELTA in AJAX callback function? (See above)

UPDATE (NOT WORKING!)

I managed to figure out a workaround to make this work as following:

  • Item to be updated receives an ID composed of field_name and delta (e.g. location-div-myfield-0 (this is necessary if multiple instances of the same field are on the same page)
  • Save field name (here myfield) and delta (here 0) in $field_state (in hook_field_widget_form)
  • Read the saved values from $field_state in ajax callback (here some_ajax_callback) and return the desired form element.

This however works if there is only one instance of the field in the form, otherwise the values in $form_state are always those of last instance.

Possible solution

Using the triggering_element of $form_state in some_ajax_callback all necessary info can be derived:

function some_ajax_callback ($form, $form_state)
{
    // This contains info about triggering element
    // Index 0 = field name, 1 = language, 2 = delta, 3 = element name
    $element = $form_state['triggering_element']['#parents'];
    $delta = $element[2];
    $field_name = $element[0];
    ...
}

5 Answers 5

1

I generally do something like this:

function gft_enable_display_callback($form, $form_state) {
  // Get the array parents of the triggering element
  $parents = $form_state['triggering_element']['#array_parents']; 
  // Pop off the triggering element as we usualy want the one above it
  array_pop($parents);
  // Get the element from the nested array
  $element = drupal_array_get_nested_value($form, $parents);

  return $element; // or we can return $element['someotherfield']
}

We can also use the drupal_array_get_nested_value to retrieve values from form_state['values'] as needed.

0

I had the same problem. I could solve this by just using

  • $element['#parents'][0] for the field name
  • $element['#delta'] for delta

This works with a multivalued field.

0

Since you can access the submit button form element in the AJAX callback, using $form_state['triggering_element'], you could add some identifier to the submit button. For example, in your hook_widget_form():

$element['value']['#ajax'] = array(
  'callback' => 'some_ajax_callback',
  'wrapper' => 'location-div',
  'method' => 'replace',
  'effect' => 'fade'
);
$element['value']['#name'] = 'submit_field_name_FIELD_NAME';

and then in your AJAX callback:

$submit_name = $form_state['triggering_element']['#name'];
$field_name = str_replace('submit_field_name_', '', $submit_name);

You could do something similar to get the field delta (i.e. use submit_field_name_FIELD_NAME_delta_DELTA, and use some regex or something to extract both). This links the field name and delta directly to the submit button, so even if you had multiple fields and deltas, it would be easy to figure out which one each particular submit button applies to.

0

Add another property to the form element that contains the delta it had when it was built. In your AJAX callback you can retrieve this delta via the triggering element value.

$element[$delta]['value']['#element_index'] = $delta;
$element[$delta]['value']['#ajax'] ...;

And in your AJAX callback

$delta = $form_state['triggering_element']['#element_index'];

This lets you explicitly set and get the delta without relying on pulling it from other data.

0

This should help for Drupal 8/9:

function some_ajax_callback ($form, $form_state) {
  $trigger = $form_state->getTriggeringElement();
  $parents = NestedArray::getValue($form, array_slice($trigger['#array_parents'], 0, -1));
  ...
}

Don't forget to include Drupal\Component\Utility\NestedArray

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.