2

I am designing a site that has a variety of points in which I need to render "workflow" buttons that are used to send actions to an external application.

I used the form API to generate these buttons, and am using the #submit => option on my buttons to direct specific button types to custom functions. I am also using hidden fields to house data that I use to facilitate the action.

The problem I am having is that these buttons can and should show up multiple times per page, for different aspects of the application, and whenever I click one of the buttons Drupal attempts to submit all of the forms.

I guess what i am asking is, how can I have multiple instances of the exact same form on screen at any given time, and know with certainty that the submit buttons are only going to trigger actions for the specific instance of the form they belong to?

thanks in advance!!

Edit

So here is the crux of the problem - it appears that the getFormId needs to return a unique value, but I cannot figure out how to pass unique values into it.

  • 1
    Since you did not provide any code, I am just guessing here. Probably because each form needs have a unique ID and maybe also a unique class name. – No Sssweat Dec 18 '16 at 6:17
3

Yes, each form must have a unique form ID. See https://www.drupal.org/node/766146 and the comments there.

You need to find something that uniquely identifies each form and put that in the form ID.
As commented there, that can be a bit tricky as getFormId() is called very early, so you need to instantiate the form object yourself and pass it to the form builder.

See FormBuilder::getFormId() for what happens when you pass in a string, it is passed to $this->classResolver->getInstanceFromDefinition($form_arg);, that creates the object and uses the create() method if available, you can use that or just do it yourself with a new Object(), then pass that to getForm() instead.

  • Okay, I think I get that, but I do not see how to pass values to getFormId() so that I can instantiate it properly. – Kelly Kamm Dec 18 '16 at 17:21
  • How do I self-instantiate a form object? Any help would be greatly appreciated. Right now I am using the $workflowForm = \Drupal::formBuilder()->getForm('\Drupal\foo\Form\Bar', $build['#actions'], $sr->Id, 'sr'); style command - at what stage should I be hopping in and extending the process? – Kelly Kamm Dec 18 '16 at 19:23
  • Did you see the code in the simplenews module that is referenced in that issue? You can pass an object to getForm() and you can create that in any way you want. I'll update my comment with some references. – Berdir Dec 18 '16 at 19:35
  • 2
    This got me exactly on the right path, and my forms are instantiating exacly as I want them to. Turns out it is as simple as doing a $form['#attributes']['id] = $MY_UNIQUE_VARIABLE when setting up the form array in buildForm. On a page with 10 forms and everything is working as desired. – Kelly Kamm Dec 18 '16 at 20:25
6

You could also add something like this to your form class

 /**
  * Keep track of how many times the form
  * is placed on a page.
  *
  * @var int
  */
protected static $instanceId;

/**
 * {@inheritdoc}
 */
public function getFormId() {
  if (empty(self::$instanceId)) {
    self::$instanceId = 1;
  }
  else {
    self::$instanceId++;
  }

  return 'my_form_id_' . self::$instanceId;
}
  • This worked for me ! You have juste one space just after id in your return to remove: return 'my_form_id _' . self::$instanceId; -> return 'my_form_id' . self::$instanceId; – Christophe CARON Jun 27 at 9:58
  • Good catch, I updated it. – pwaterz Jun 28 at 14:10
  • Great answer, worked for me as well! Surprisingly, this is not built into the Form base class – ryrye Sep 12 at 16:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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