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 #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',
],
];
}
audacus β created an issue.
audacus β created an issue.
audacus β made their first commit to this issueβs fork.