- 🇩🇪Germany Anybody Porta Westfalica
Just ran into this issue in Homebox and think I can add a good example from there:
All Homebox portlets (boxes) are separate forms, based on the same form (id). So there can be unlimited number of these "same" forms on the same page.
Technically, they are extending
PluginBase
and implement FormInterface. (The ECA module does similar things and for this software design, this is needed).Here's the class implementation:
abstract class HomeboxPortletTypeBase extends PluginBase implements HomeboxPortletTypeInterface, ConfigurableInterface, PluginFormInterface, ContainerFactoryPluginInterface, FormInterface
When implementing the AJAX functionality, I was wondering, why
$form_state->getTriggeringElement();
always returned the wrong element! It always returned the first buttom from the very first instance of the form on that page.
The interesting part is, that the AJAX call body contained the clicked element as triggering element.So I tried changing the getFormId() implementation in that plugin from:
/** * {@inheritdoc} */ public function getFormId() { return 'homebox_portlet_form'; }
to
/** * {@inheritdoc} */ public function getFormId() { return 'homebox_portlet_form' . $this->getDelta(); }
and it works!
But it cost me hours to find this.I guess the reason for this is a security check in the form to ensure the AJAX-given triggering element exists.
Perhaps a first step would be to log a watchdog warning in such a case to let the developer know the mismatch?Hopefully my implementation for the dynamic form ID won't have other side-effects! For now it works...
So this is still an issue in 11.x-dev!
Had same problem,
I have multiple same forms on one page generated in loop.
I met the problem when I wanted to inject HttpClient to Form but back then was passing customValue through constructor.My approach to solve this issue was define Form as service and pass custom id via property setter:
.services.yml
services: my_module.my_form: class: Drupal\my_module\Form\MyForm arguments: [ '@http_client' ] tags: - { name: form }
CustomClass:
$form_as_service = \Drupal::service('my_module.custom_form'); $form_as_service->setCustomValue($custom_value); $form = $this->formBuilder->getForm($form_as_service, $additional_parameters);
Form Class:
protected string $customValue; public function setCustomValue(string $value) { $this->customValue = $value; } public function getFormId() { return 'base_id_'.This->customValue; }
Maybe it's not ideal, but I think it could be helpful for others.
- 🇮🇳India sukr_s
An alternate solution if multiple forms with different constructor values are rendered on same page #2821852-41: The same form twice on one page with different arguments may process the wrong form when submitted →