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?

Comments

koosvdkolk created an issue. See original summary.

jvdkolk’s picture

Issue summary: View changes
jvdkolk’s picture

Issue summary: View changes
jvdkolk’s picture

Issue summary: View changes
jvdkolk’s picture

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;
}
jvdkolk’s picture

Status: Active » Needs review