0

I have a form with a second button which should add new form elements according to this page. The callback does not get called though. The second button is set from the following code.

$form[ 'addTicket' ] = array(
  '#type' => 'submit',
  '#submit' => array('asdf'),
  '#value' => 'Add Ticket'
);

Clicking it should, as of my understanding, call this callback function.

function asdf() {
  error_log( 'I was called' );
}

It is never called though. Why? Is there a way to debug this?

This is the complete code.

function WPD14_menu() {
    $items = array();
    $items[ 'WPD14/anmeldung' ] = array(
        'title' => 'Anmeldung zum World Photography Day 2014',
        'page callback' => 'WPD14_anmeldung',
        'access arguments' => array( 'access content' ),
        'description' => 'Anmeldung zum WPD 14',
        'type' => MENU_CALLBACK,
    );
    return $items;
}

function WPD14_anmeldung() {
  return drupal_get_form('WPD14_anmeldeformular');
}

function asdf($form, &$form_state) {
  error_log('asdfasdfasdfs');
}

function WPD14_anmeldeformular($form_state) {
  $form['buyer'] = array(
    '#type' => 'fieldset',
    '#title' => 'Infos',
  );

  $form['buyer']['strasse'] = array(
    '#type' => 'textfield',
    '#title' => 'Strasse + Nr.',
    '#required' => TRUE,
    '#default_value' => isset($form_state['storage']['buyer']['strasse']) ? $form_state['storage']['buyer']['strasse'] : 'Strasse',
  );

  $form['buyer']['plz'] = array(
    '#type' => 'textfield',
    '#title' => 'PLZ',
    '#required' => TRUE,
    '#default_value' => '1234'
  );

  $form['buyer']['ort'] = array(
    '#type' => 'textfield',
    '#title' => 'Ort',
    '#required' => TRUE,
    '#default_value' => 'There'
  );

  $form['buyer']['mail'] = array(
    '#type' => 'textfield',
    '#title' => 'Mailadresse',
    '#required' => TRUE,
    '#default_value' => '[email protected]',
  );

  $nTickets = isset($form_state['storage']['nTickets']) ? intval( $form_state['storage']['nTickets']) : 2;
  $nTickets = min(20, max(1, $nTickets));

  $form['nTickets'] = array(
    '#type' => 'textfield',
    '#title' => 'Anzahl Tickets',
    '#disabled' => FALSE,
    '#default_value' => $nTickets,
  );

  for ($t = 0; $t < $nTickets; $t++) {
    $form['tickets'][$t] = WPD14_ticketformular($t);
  }

  $form['addTicket'] = array(
    '#type' => 'submit',
    '#submit' => array( 'WPD14_anmeldeformular_addTicket', 'asdf' ),
    '#value' => 'Weiteres Ticket'
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Anmelden',
  );

  return $form;
}

function WPD14_anmeldeformular_addTicket($form, &$form_state) {
  error_log('Callback called.');
  error_log($form_state['nTickets']);
  $form_state['nTickets']++;
  // $form_state['rebuild'] = TRUE;
  drupal_set_message($form_state['nTickets']);
}

function WPD14_ticketformular($nr) {
  $form = array(
    'vorname-' . $nr => array(
      '#type' => 'textfield',
      '#title' => 'Vorname',
      '#required' => TRUE,
      '#default_value' => 'Vorname ' . $nr
    ),
    'nachname-' . $nr => array(
      '#type' => 'textfield',
      '#title' => 'Nachname',
      '#required' => TRUE,
      '#default_value' => 'Nachname ' . $nr
    ),
    'frMain-' . $nr => array(
      '#type' => 'textfield',
      '#title' => 'Hauptvortrag Freitag',
      '#required' => TRUE,
      '#default_value' => 'Fr H ' . $nr
    ),
    'saDay-' . $nr => array(
      '#type' => 'textfield',
      '#title' => 'Nachmittagsvorträge',
      '#required' => TRUE,
      '#default_value' => 'Sa ' . $nr
    ),
    'saMain-' . $nr => array(
      '#type' => 'Hauptvortrag Samstag',
      '#title' => 'Name',
      '#required' => TRUE,
      '#default_value' => 'Sa H ' . $nr
    ),
  );

  return $form;
}


function WPD14_anmeldeformular_validate($form, &$form_state){
  if (!preg_match( '/^[a-z0-9]+([_.-][a-z0-9]+)*@([a-z0-9]+([.-][a-z0-9]+)*)+\\.[a-z]{2,4}$/', $form_state['values']['mail'])) {
    form_set_error('mail','Bitte geben Sie eine gültige Mailadresse an.');
  }

  $nTickets = intval($form_state['values']['nTickets']);
  if ($nTickets < 1) {
    form_set_error('nTickets','Kein Ticket ausgewählt.');
  }

  form_set_error('debug', print_r($form_state, TRUE));
}
5
  • 2
    It should work like that. Can you give us more code?
    – berliner
    Commented Sep 9, 2014 at 23:16
  • Full code added. Commented Sep 10, 2014 at 19:30
  • 1
    It seems I have found the bug. It is the very last line in the full code example, form_set_error, which is always executed, and all other callbacks are skipped. Commented Sep 10, 2014 at 20:40
  • 1
    You should probably mark your answer with the check mark to indicate this has been solved.
    – htoip
    Commented Sep 11, 2014 at 3:14
  • Stack did not allow this, had to wait one day ;) Commented Sep 11, 2014 at 9:15

3 Answers 3

3

Remove the form_set_error() call that always gets called in wpd14_anmeldeformular_validate(). This tells Drupal that the form did not validate and Drupal will not call the submission handlers.

Other changes you will need to make are in the hook_menu() implementation, and in the form name method. Here's what your hook_menu() should look like.

function wpd14_menu() {
  $items = array();
  $items['wpd14/anmeldung'] = array(
    'title' => 'Anmeldung zum World Photography Day 2014',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('wpd14_anmeldeformular'),
    'access arguments' => array('access content'),
    'description' => 'Anmeldung zum WPD 14',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

Note the change for 'page callback' and the addition of 'page arguments'. Finally, the arguments of wpd14_anmeldeformular are incorrect. They should be as follows.

function wpd14_anmeldeformular($form, &$form_state) {
  // ...
}
3
  • Thanks for the additional information. Is there another advantage of drupal_get_form as page callback except for not requiring the additional function? (I'm going to need it to prepend some HTML etc, at the moment it is useless though.) Commented Sep 11, 2014 at 9:22
  • 1
    I think calling drupal_get_form in a page callback function, or using drupal_get_form as the page callback function, doesn't necessarily give a huge advantage. If you look at other menu items that return a form, drupal_get_form is typically used. You do have the option of adding markup to the form if that's the only reason for not using drupal_get_form. Using form #type='item', for example, is one way to prepend HTML.
    – Evil E
    Commented Sep 12, 2014 at 12:49
  • Regarding the $form, &$form_state: When using it like that, I get a warning: Missing argument 2 for WPD14_anmeldeformular() and additionally a white screen when trying to submit. So, it only works with one parameter. Commented Sep 12, 2014 at 19:04
1

Try adding a custom "#name" value to the button. Drupal defaults to having a name of 'op' for buttons, so it's likely thinking they're the same button and only calling the one callback.

2
  • Added a unique #name to both submit buttons, but it did not change anything. Commented Sep 10, 2014 at 20:22
  • No. But I have ensured drupal did not run outdated code. :) Commented Sep 10, 2014 at 20:40
1

The bug was, as already noted in the comment, that the _validate hook failed and prevented all further callbacks. So, even for the custom submit button, the validate hook was called first.

Necessary changes were removing the last line in function WPD14_anmeldeformular_validate( $form, &$form_state ), changing the callback function as follows

function WPD14_anmeldeformular_addTicket( $form, &$form_state )
{
    $form_state['values'][ 'nTickets' ]++;
    $form_state['rebuild'] = TRUE;
}

and use $form_state['values'] instead of 'storage' everywhere; What is $form_state used for? explained this.

$nTickets = isset( $form_state[ 'values' ][ 'nTickets' ] ) ? intval( $form_state[ 'values' ][ 'nTickets' ] ) : 2;
$nTickets = min( 20, max( 1, $nTickets ) );

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.