How to alter values of form elements based on other values

Created on 10 October 2023, 12 months ago
Updated 11 October 2023, 12 months ago

The situation

I have a node form with an inline entity form, allowing users to add 1...n instances of entity X.

In the form of entity X, I have two selects A and B.

The challenge

What I want to achieve, is to limit the options of select B , based on the selected value of select A.

What I tried

Using hook_inline_entity_form_entity_form_alter I added an #ajax change event to select A. This triggers a callback

function mymodule_ajax_callback(array &$form, \Drupal\Core\Form\FormStateInterface $form_state) {

In this function the fun ends.

The problem

The (recurring) problem with IEF is that $form and $form_state always contain the complete form (in this case: the node form) data and not the inline entity form data, so data of the current entity X form.

Next, there seems to be no foolproof way of obtaining the values of the current entity X form

In my mymodule_ajax_callback function I now have something like

$myvar = $form_state->getUserInput()['field_a']['form']

but the value of $myvar seems quite random:
- it sometimes contains a key 'inline_entity_form' with nested values
- it sometimes contains numeric keys with nested values

Somewhere hidden in these nested value is the currently selected value of A, but I do not know how to know which one to take, as in theory, the end user could have multiple IEF open.

My question

How to obtain the value of select A of entity X the user is currently editing and set the options of select B of the entity X the user is is currently editing?

💬 Support request
Status

Needs review

Version

2.0

Component

Documentation

Created by

🇳🇱Netherlands koosvdkolk

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @koosvdkolk
  • 🇳🇱Netherlands koosvdkolk

    Got it to work:

    /**
     * Implements hook_inline_entity_form_entity_form_alter.
     *
     * @return void
     */
    function my_module_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
      if ($entity_form['#entity_type'] == 'my_entity_type' && $entity_form['#bundle'] == 'my_entity_bundle') {
        $element_id = join('_', $entity_form['#parents']); // Obtain unique id for the wrapper
        $entity_form['select_a']['widget']['#ajax'] = [
          'callback' => 'my_module_form_select_update_ajax_callback',
          'event' => 'change',
          'wrapper' => $element_id,
        ];
        $entity_form['select_b']['#prefix'] = '<div id="'. $element_id .'">';
        $entity_form['select_b']['#suffix'] = '</div>';
      }
    }
    
    /**
     * Ajax callback.
     *
     * @param array $complete_form
     * @param \Drupal\Core\Form\FormStateInterface $form_state
     *
     * @return array
     */
    function my_module_form_select_update_ajax_callback(array &$complete_form, \Drupal\Core\Form\FormStateInterface $form_state) {
      $select_a_form_element = $form_state->getTriggeringElement();
      $selected_entity_id = (int) $select_a_form_element['#value'];
    
      // Find select b in the form.
      $form_part = NestedArray::getValue($complete_form, array_slice($select_a_form_element['#array_parents'], 0, -2));
      $select_b_form_element = $form_part['select_b'];
    
      // Get options.
      $options = [];
      if ($selected_entity_id>=0) {
        // Add options here based on the entity id.
      }
    
      // Return new select b.
      $select_b_form_element['widget']['#options'] = $options;
      return $select_b_form_element;
    }
    
  • Status changed to Needs review 12 months ago
Production build 0.71.5 2024