Drupal 8 programmatically create a custom form with multiple submit buttons

user6742604 picture user6742604 · Feb 1, 2017 · Viewed 10.4k times · Source

I have a custom Drupal 8 form that shows a list of users and a "check" button for each user.

When clicking a check button, the submit handler needs to figure out which users "check" button was clicked.

I've tried this the following way, but it always returns the id of the last element instead of the correct element.

Is this a bug in Drupal Core Form API?

Any other way to do this? I'm open to suggestions!

This is just an example. What I'm actually trying to do is show a list of users that belong to a specific 'company' node. In that list there is a 'remove from company' button for each user.

http://pastebin.com/us2YFcjr

<?php

namespace Drupal\form_multi_submit\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\user\Entity\User;

class MultiSubmitForm extends FormBase {

  public function getFormId() {
    return 'MultiSubmitForm';
  }

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

    // Get all users from database
    $ids = \Drupal::entityQuery('user')
      ->condition('status', 1)
      ->execute();
    $users = User::loadMultiple($ids);

    // Set form table header
    $form['users'] = array (
      '#type' => 'table',
      '#header' => array('ID', 'Remove'),
    );


    // Loop through all users
    foreach ($users as $user) {

      // Show user ID
      $form['users'][$user->id()]['id'] = array(
        '#type' => 'label',
        '#title' => $user->id(),
      );

      // Show button for each user
      $form['users'][$user->id()]['removememberbutton']['dummyNode'] = array(
        '#type' => 'submit',
        '#value' => 'Check',
        '#submit' => array([$this, 'removeMember']),
      );
    }

    return $form;
  }


  // Submit handler
  public function removeMember(array &$form, FormStateInterface $form_state) {
    $userid = $form_state->getTriggeringElement()['#array_parents'][1];
    drupal_set_message($userid, 'status');
  }

  public function validateForm(array &$form, FormStateInterface $form_state) {
    // Nothing to do here.
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Nothing to do here.
  }

}

Answer

user6742604 picture user6742604 · Feb 1, 2017

Drupal considers buttons with the same #value as the same button, unless they have a different #name

So all I had to do was add a unique #name to my buttons to get this to work properly:

$form['users'][$user->id()]['dummyNode-' . $user->id()] = array(
  '#type' => 'submit',
  '#value' => 'Check',
  '#name' => 'check_' . $user->id(),
  '#submit' => array([$this, 'removeMember']),
);

https://www.drupal.org/node/1342066#comment-11904090