2

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!

8
  • 1
    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?
    – berliner
    Dec 9, 2021 at 11:21
  • 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.
    – Auraylien
    Dec 9, 2021 at 13:44
  • 1
    No change was expected actually ;) Did you try the other notation from the documentation that you linked to? '::methodName' just in case.
    – berliner
    Dec 9, 2021 at 14:03
  • Yes, I already tried this but it does not working too :(
    – Auraylien
    Dec 9, 2021 at 14:08
  • 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.
    – berliner
    Dec 9, 2021 at 14:15

2 Answers 2

3

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

1
  • 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
    – Auraylien
    Dec 10, 2021 at 9:03
0

#submit: Specifies an alternate callback for form submission when the submit button is pressed. Use '::methodName' format or an array containing the object and method name (for example, [ $this, 'methodName'] ).

  /**
   * @param array $form
   * @param FormStateInterface $form_state
   * @return array
   */
  public function buildForm(array $form, FormStateInterface $form_state)
  {
    $form['actions'] = [
      '#type' => 'actions',
    ];

    $form['actions']['submit1'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit One'),
      "#weight" => 1,
      '#submit' => array([$this, 'submitFormOne']),
      '#limit_validation_errors' => array()
    ];

    $form['actions']['submit2'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit Two'),
      "#weight" => 2,
      '#button_type' => 'primary',
      '#submit' => array([$this, 'submitFormTwo']),
      '#limit_validation_errors' => array()
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitFormOne(array &$form, FormStateInterface $form_state)
  {
    //TODO: write your code
  }

  /**
   * {@inheritdoc}
   */
  public function submitFormTwo(array &$form, FormStateInterface $form_state)
  {
    //TODO: write your code
  }

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.