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' => 'test@example.com',
  );

  $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));
}
  • 2
    It should work like that. Can you give us more code? – berliner Sep 9 '14 at 23:16
  • Full code added. – Simon A. Eugster Sep 10 '14 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. – Simon A. Eugster Sep 10 '14 at 20:40
  • 1
    You should probably mark your answer with the check mark to indicate this has been solved. – htoip Sep 11 '14 at 3:14
  • Stack did not allow this, had to wait one day ;) – Simon A. Eugster Sep 11 '14 at 9:15
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) {
  // ...
}
  • 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.) – Simon A. Eugster Sep 11 '14 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 Sep 12 '14 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. – Simon A. Eugster Sep 12 '14 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.

  • Added a unique #name to both submit buttons, but it did not change anything. – Simon A. Eugster Sep 10 '14 at 20:22
  • No. But I have ensured drupal did not run outdated code. :) – Simon A. Eugster Sep 10 '14 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, privacy policy and cookie policy

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