- Issue created by @Murz
- π¨π¦Canada alberto56
@Murz thanks for posting this. I was going around in circles, and your post set me in the right direction. In my case as well, the triggering element seems wrong.
I would expect:
$form_state->getTriggeringElement()['#name'];
to be the same as:
$form_state->getUserInput()['_triggering_element_name'];
which it is in most cases, but in some cases the former gives me, for some reason, the first triggering element in the page whether or not that's the one I clicked.
$form_state->getUserInput()['_triggering_element_name'];
always seems right.
There is a lot of custom code in my site, so for now I cannot confirm that I'm not doing something which is causing this (although I cannot find anything).
For me, a smelly workaround is the best way forward for now. Thanks!
- π¨πSwitzerland audacus
I had a similar issue building an AJAX form with multiple items.
Each item has its own remove button. When clicking the remove button e.g. of the first item, the triggering element would still be the remove button of the last item.I tried to track the issue down and found following checks in
\Drupal\Core\Form\FormBuilder::elementTriggeredScriptedSubmission
where it will return whether the given element is triggering the submission:protected function elementTriggeredScriptedSubmission($element, FormStateInterface &$form_state) { $input = $form_state->getUserInput(); if (!empty($input['_triggering_element_name']) && $element['#name'] == $input['_triggering_element_name']) { if (empty($input['_triggering_element_value']) || $input['_triggering_element_value'] == $element['#value']) { // If the `#name` and the `#value` match the element in the user input, it is the triggering element... return TRUE; } } return FALSE; }
If you have multiple elements with the same
<!--break-->#name
and the same#value
, the triggering item will be the last item for which the above checks run through.I had something like the following:
for ($i; $i < $num_items; $i++) { $form['wrapper']['items'][$i]['actions']['remove'] = [ '#type' => 'submit', '#value' => $this->t('Remove item'), '#submit' => ['::removeItem'], '#ajax' => [ 'callback' => '::ajaxCallback', ], ]; }
Like this, every remove button had the same
#name
and same#value
, and therefore the triggering element always was the remove button of the last item.I could solve this issue by adding a unique name or value for each remove button:
for ($i; $i < $num_items; $i++) { $form['wrapper']['items'][$i]['actions']['remove'] = [ '#type' => 'submit', // Item specific name. '#name' => 'remove-item-' . $i, // Item specific value. '#value' => $this->t('Remove item @item', ['@item' => $i]), '#submit' => ['::removeItem'], '#ajax' => [ 'callback' => '::ajaxCallback', ], ]; }