I have a node add form with some integer text fields that have unlimited cardinality, which causes an AJAX 'Add More' button to be displayed for those fields. The form also has a custom submit handler that is defined in a custom module.

  function formalter_form_alter(&$form, $form_state, $form_id) {

$form['actions']['gaylord_submit'] = array(
  '#type' => 'submit',
  '#value' => t('Add Gaylord'),
  '#submit' => array('inventory_stocking_ticket_form_gaylord_submit'),
  '#executes_submit_callback' => TRUE,
  '#name' => 'edit-gaylord-submit',
  '#limit_validation_errors' => array(),
);

function inventory_stocking_ticket_form_gaylord_submit(&$form, &$form_state) {
if ($form_state['clicked_button']['#id'] == 'edit-gaylord-submit') {
  node_form_submit($form, $form_state);

//do custom stuff here

}
}

Here's my problem: If the custom submit handler function is defined inside the hook_form_alter function & there are no unlimited cardinality fields, everything works great, node is created or modified, form values are saved, & my custom submit handler stuff is performed. If, however, I have a field with unlimited cardinality & my custom submit handler function is defined inside the hook_form_alter function, I receive an error: PHP Fatal error: Call to undefined function inventory_stocking_ticket_form_gaylord_submit() in /hosting/somesite/com/htdocs/cms_sandbox/includes/form.inc on line 1464 & a white screen of death. If I move the custom submit handler function outside of the hook_form_alter, there's no error even with unlimited cardinality fields, the node is created or modified, & my custom submit handler stuff works, but field values are not saved.

I've further discovered that commenting out the code that creates the AJAX 'Add Another' button in core's field.form.inc makes everything work, even with the submit handler inside the hook_alter & unlimited cardinality fields. Of course there's no 'Add Another' button now, defeating the purpose of having unlimited fields.

I have two questions:

  1. What is causing the conflict & PHP error when the submit handler inside the hook_form_alter is combined with unlimited cardinality fields?

  2. Why won't the custom submit handler save field data when it is defined outside of the hook_form_alter?

If I could solve either of these problems I'd have what I needed. Any help is hugely appreciated.

  • plz specifiy the drupal version. – Ankit Chauhan Mar 13 '13 at 9:47
  • Drupal 7.21, MySQL 5.1.63, PHP 5.3.14 with Suhosin-Patch, Apache/1.3.29 (OpenBSD version) – hclayton Mar 14 '13 at 2:49

try this:

function formalter_form_alter(&$form, $form_state, $form_id) {
  // override the default submit
  $form['#submit'] = array('inventory_stocking_ticket_form_gaylord_submit');
  // include the default submit and your custom submit
  //$form['#submit'][] = 'inventory_stocking_ticket_form_gaylord_submit';
}

function inventory_stocking_ticket_form_gaylord_submit(&$form, &$form_state) {
  if ($form_state['clicked_button']['#id'] == 'edit-gaylord-submit') {
    node_form_submit($form, $form_state);

    //do custom stuff here

  }
}
up vote 0 down vote accepted

Solved both questions.

  1. It's a hack, but I was able get everything working by including the custom submit handler function by putting it in an external .inc file & using a require_once line in the custom module outside any function therein to include it. This still fails when I make fields required & bypass the requirement with the custom submit button (data not saved); however, I don't need this because I figured out #2.

  2. The real problem was that I was making fields required, then needed to bypass validation of 'required' status when using the custom submit button. I was doing this by using '#limit_validation_errors' => array(),. The problem is that unvalidated values are removed from $form_state['values'] when using #limit_validation_errors and therefore not saved, which is why everything worked with the custom submit except saving the data input into required fields. See https://drupal.org/node/763376

To solve this, I lifted & modified some code from a patch to the Save Draft module (the patch).

My custom module now includes the following:

  function formalter_form_alter(&$form, $form_state, $form_id) {

$form['actions']['gaylord_submit'] = array(
  '#type' => 'button',
  '#value' => t('Add Gaylord'),
  '#submit' => array('inventory_stocking_ticket_form_gaylord_submit'),
  '#executes_submit_callback' => TRUE,
  '#name' => 'edit-gaylord-submit',
//  '#limit_validation_errors' => array(), //values in required fieldsnot saved with this
  '#skip_required_validation' => TRUE, //add new property to custom submit button
);
$form['#after_build'][] = 'inventory_after_build';
}

function inventory_after_build($form, &$form_state) {
  // Check that the form has been submitted.
  if ($form_state['process_input']) {
    // If the gaylord_submit button was pressed.
    if (!empty($form_state['triggering_element']['#skip_required_validation'])) {
      _gaylord_submit_remove_required($form);
    }
}
return $form;
}

function _gaylord_submit_remove_required(&$elements) {
  // Recurse through all children.
  foreach (element_children($elements) as $key) {
    if (isset($elements[$key]) && $elements[$key]) {
      _gaylord_submit_remove_required($elements[$key]);
    }
  }
  if (!empty($elements['#required'])) {
    $elements['#required'] = FALSE;
  }
}

function inventory_stocking_ticket_form_gaylord_submit(&$form, &$form_state) {
if ($form_state['clicked_button']['#id'] == 'edit-gaylord-submit') {
  node_form_submit($form, $form_state);

//do custom stuff here

}
}

And it works perfectly! A new property is added to the custom submit button. An after_build function is called that checks if the form has been submitted by the custom button with the new property, & if so, calls a function that recurses through all the form fields & removes the #required property from any that have it. All other form validation is preserved. And the data input into the (formerly0 required fields is saved.

Maybe this will help someone. Cheers.

This may be relevant: form_load_include. Including external files needs to be done differently in form code because of caching.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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