0

I have a form with a nested subform that has an ajax submit button in it. The subform is built inside a form_alter and attached to the form. The submit buttons #name is made unique by using a UUID generator.

When I press the ajax submit button, Drupal steps through its form builder steps rebuilding the form. Because of this, the same code in the form_alter is called rebuilding the same subform. The problem is that when it is rebuilt, the submit button gets a brand new #name via the UUID generator. As such, Drupal cannot match the _triggering_element to a #name, and the ajax fails.

One solution I thought to try was to attach the #name to $form_state storage when the form is first built hoping that it would be available when the form is rebuilt. For e.g. in the same form_alter I execute:

      $input = $form_state->getUserInput();
      if($input){
        //This only runs when the form is being rebuilt
      }

And I may be able to grab the correct #name out of $form_state storage and set it so Drupal can correctly match and find the right ajax callbacks.

Is something like this possible? Is there a better way to handle this?

1
  • 1
    What I can tell you is that in nearly 15 years of using Drupal, I have only ever found setting #name to cause issues. Better to leave that one alone. Not sure what you're trying to do though, so can't really help with a solution.
    – Jaypan
    Commented Mar 5, 2021 at 3:03

1 Answer 1

1

You only need #name if the form array keys don't provide a unique path for form_state. I agree with @Jaypan, I too found setting #name never really necessary, it seems to be more reliable to define a unique key to the lowest level of the form element if you have issues with Ajax not finding the form element. In either case, #name or form key, it has to be predictable, derived from data which doesn't change between form builds, for example a field delta.

The form object and $form_state are not cached when a form is rendered, only after submitting the first Ajax request. So it doesn't help to store data in $form_state you want to use to rebuild $form.

4
  • The form that gets built within the node edit form exists in a certain Paragraph type. So if more than one of these paragraphs is added to the page, I'm not quite sure how I'd get away with not using a UUID generator to either create unique keys or a unique #name. Is your intuition that it would work better if the generate was acting on the keys instead of the #name?
    – plambre
    Commented Mar 5, 2021 at 14:31
  • It needs to be unique only within the form, so it should work if you add the field delta of the paragraph reference field to #name or form array key.
    – 4uk4
    Commented Mar 5, 2021 at 14:37
  • Ah that makes sense, use the ordering on the fields to make the names or keys unique. Now in my case, each relevant field on the Node is a Paragraph which references a Paragraph. The $form array I get is like ['field_name']['widget'][0] where the [0] array does have a '#delta' value, but in my case its always 0 because there aren't other items in ['widget'] (and there will only ever be 1). I noticed at the $form['field_name'] level there is a 'weight' key with a changing value. Could that potentially be used in the same way?
    – plambre
    Commented Mar 5, 2021 at 14:51
  • To any who find this question: 4k4 led me down the right path. I was building the form in a hook_field_widget_WIDGET_TYPE_form_alter so there was not a unique delta available, but in the 3rd argument (context) the machine name of the parent field is provided in a few places. This machine name has to be unique within the Node, so I used it to assign the #name value instead of a UUID and ajax started working.
    – plambre
    Commented Mar 5, 2021 at 15:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.