Score:2

Form with two submission buttons

th flag

I try to create a form with two submit buttons and each button will use a different function: the default submitForm function and a custom submitFormEndSession function. So I have this code:

class EndSessionForm extends FormBase {

  /**
   * @var \Drupal
   */
  private $drupal;

  public function __construct() {
    $this->drupal = new Drupal();
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'end_session_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state): array {

    // ... some fields

    $form['submit'] = [
      '#type' => 'submit',
      '#value' => 'Close the session',
      '#name' => 'btnEnd',
    ];

    $form['stop'] = [
      '#type' => 'submit',
      '#value' => 'Stop the session',
      '#name' => 'btnStop',
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Function to call with the btnEnd button
  }

  public function submitStopForm(array &$form, FormStateInterface $form_state) {
    // Function to call with the btnStop button
  }
}

According to the documentation of Drupal 9.2.x, the only thing I had to do is add a #submit parameter to the $form['stop'] element like this:

$form['stop'] = [
  '#type' => 'submit',
  '#value' => 'Stop the session',
  '#name' => 'btnStop',
  '#submit' => [ $this, 'submitStopForm' ] // link to the second submit function
]

But it doesn't work.

After many tries and researches, I've found a partial solution by adding this in buildForm:

$form['#submit'][] = [$this, 'submitStopForm'];

The two buttons are now linked to submitForm and submitStopForm, no matter if I put a #submit parameter on the buttons or not, submitStopForm is executed first then submitForm. But I'm wonder how I can link the first button to submitForm and the second one to submitStopForm properly and without enter in both functions when we click on one button.

Thanks and have a nice day!

berliner avatar
bd flag
Hi and welcome to Drupal Answers! I have a comment that is not directly related to your question: Your constructor looks very strange. You don't usually need a constructor for form classes if you don't want to inject services. And I have never seen `new Drupal()` anywhere inside custom code. May I ask where you got that from and why you use that?
Auraylien avatar
th flag
Hi @berlinern, this code isn't my proper code, so I can't explain the `$this->Drupal = new Drupal()` instruction. When we got this project, it was on Drupal 8 and we made several updates to the latest Drupal version, so maybe it's deprecated code. I removed it (and the constructor too) and nothing change.
berliner avatar
bd flag
No change was expected actually ;) Did you try the other notation from the documentation that you linked to? `'::methodName'` just in case.
Auraylien avatar
th flag
Yes, I already tried this but it does not working too :(
berliner avatar
bd flag
Can you post your full real code for the content of your submit functions (or a minimal example that reproduces your problem)? There is something odd there. All submit functions set in `$form['#submit']` should be called, not only the first one.
Auraylien avatar
th flag
That was a mistake from me: I wrote `die()` in both with a comment for testing which function I could reach. So, I reach first `submitStopForm` then `submitForm`. But what I wanted is to reach immediatly `submitStopForm` or `submitForm`, depend of the button, and putting `#submit => [$this, 'submitStopForm']` under a button parameters not works
berliner avatar
bd flag
Please update your question accordingly. That will increase your chances of getting an answer.
Kevin avatar
in flag
Yes, please add the _actual_ code being used.
Score:1
cn flag

I think you have to wrap the sumbit callback in another array, if you are using that callable notation. So either:

$form['stop'] = [
  '#type' => 'submit',
  '#value' => 'Stop the session',
  '#name' => 'btnStop',
  '#submit' => [ [$this, 'submitStopForm'] ] // Array of callables (which are arrays)
];

or this

$form['stop'] = [
  '#type' => 'submit',
  '#value' => 'Stop the session',
  '#name' => 'btnStop',
  '#submit' => [ 'submitStopForm' ] //Array of submit functions
]

You can also get the element that triggered the action from inside the submit function, but i tend to think the previous solution is better.

public function submitForm(array &$form, FormStateInterface $form_state) { 
    $submitButton = $form_state->getTriggeringElement(); 
    dump($sumbitButton); 
}

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21FormState.php/function/FormState%3A%3AgetTriggeringElement/8.2.x

Auraylien avatar
th flag
Thanks for your response. `'#submit => [ [ $this, 'submitStop' ] ]` works, but only if I put the `#submit` parameter on the first button. Write it on the second button has nos effect. And put it on the first button change the handler for both buttons. And if I use your second solution, both buttons has the same trigger element, I don't understand why
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.