Complex form - merge of two with single callback I have a complex form of two logical parts, which I have placed in different  functions (my_module_partner_form &amp; my_module_fields_form). Both forms have submit handlers (my_module_partner_form - 1 submit, my_module_fields_form - 2 different submits). I would like to display those on one page.

So my solution was the following: 

Create a menu item like the following:

$items['complex-form/%/%/%'] = array(
    'title'         =&gt; 'Complex Form',
    'page callback'     =&gt; 'drupal_get_form',
    'page arguments'    =&gt; array('my_module_complex_form', 1, 2, 3),
    'access callback'   =&gt; 'my_module_complex_form_custom_access',
    'access arguments'  =&gt; array(1, 2, 3),
    'type'          =&gt; MENU_NORMAL_ITEM,
    'file'          =&gt; 'includes/some_file.inc',
);


Create a callback function to handle it

function my_module_complex_form($form, &amp;$form_state, $param1, $param2, $param3)
{
    // ... some irrelevant code here ...

    $form = array();
    $form = drupal_get_form('my_module_partner_form', $someParam);
    $form += drupal_get_form('my_module_fields_form', $someParam);

    return $form;
}


Here are the forms itself (code obfuscated)

function my_module_fields_form($form, &amp;$form_state, $param1)
{
    // ... some irrelevant code here ...

    $form['save_all'] = array(
        '#type'     =&gt; 'submit',
        '#value'    =&gt; 'Update',
    );
    $form['save_with_no_changes'] = array(
        '#type'     =&gt; 'submit',
        '#value'    =&gt; 'Save with no changes',
    );

    return $form;
}

function my_module_partner_form($form, &amp;$form_state, $param1)
{
    // ... some irrelevant code here ...

    $form['save_profile'] = array(
        '#type'     =&gt; 'submit',
        '#value'    =&gt; 'Save contact details',
    );

    return $form;
}


SO, the question is: what am I missing, as the submit function for each of the functions (except for the my_module_complex_form_submit - why?) is being called, but I can not identify which button was clicked.

What I have already tried, not to waist your time:


reading $form_state['clicked_button']['#value'] - always the same - "Update".
creating custom #submit elements for each button - this will not work as I only need one handler to work each time. Please correct me if I missed smth in the workflow.


Any ideas welcome.
When you submit a form, either by clicking a button or pressing enter, the first (by default) submit button is assumed clicked, that's why the value is always "Update".

When you submit a form, every enabled element of the form is submitted, so the #submit parameter doesn't do for you.

The complex_form_submit is not executed because you are building it using two forms with their own _submit. This way, the drupal_get_form() call doesn't link the complex form submit to the complex form.



ok, because of the reasons above, you can't proceed like that, but you still have several options:

option 1

I'm assuming that when you save, you're looking for the #value of some select/textfield/etc of your field_form, but when you save without changes, you use the #default_value of said elements for example.

If this is the case, can you consider the option to turn the save_without_change button from a submit to a reset button?

This way, the user will revert all changes to the form elements, then click on save, and you will only need one _submit callback that just save the #value.
You should still split field and partner forms like shown at the bottom of page anyway.

Drupal wont let you create reset buttons, but you can specify one like this:

$['reset'] = array( '#markup'=&gt;'&lt;button type="reset"&gt;Revert changes&lt;/button&gt;');


if #markup doesn't work, use #prefix instead.

option 2

Split the field form into two forms.

The save form will be exactly like the field one, but with a button less.

The save without changes form instead, will only have the missing button, and will store the form parameters or default values you need into elements like:

$['#val1'] = $val1;


that wont be rendered, but that you can use inside its submit for its logic.

option 3

if you really want to keep the field form like that, the only workaround i can think of is adding a hidden checkbox to your field form, and adding an onclick event to one of the two save buttons.

The event will call a JavaScript function that change the checkbox value.

Later on, inside your field_form_submit, you can use the checkbox value to evaluate which button was clicked and execute the correct logic.

downside: JavaScript have to be enabled.
you still split partner and field forms.

split

The problem here is that the two "sub" forms don't really exist anymore, they are rendered as one, which you should be able to confirm inspecting the resulting html.

If you need that only one submit is sent, don't mix them up.

Use my_module_complex_form as page callback, fix arguments accordingly, and inside render each form with drupal_render():

function my_module_complex_form(.....)
{
  // ... some irrelevant code here ...

  $f1 = drupal_get_form('my_module_partner_form', $someParam);
  $f2 = drupal_get_form('my_module_fields_form', $someOtherParam);

  $page = drupal_render($f1);
  $page .= drupal_render($f2);

  return $page;
}