22

I've got two forms in a same page.

My problem is when I tried to submit a form, it's like it tried to submit the second form below in the page as well.

As follow, you can find my 2 forms :

public function createSuiviForm() {

    return $form = $this->createFormBuilder(null)
            ->add('numero', 'text', array('label' => 'N° : ',
                'constraints' => array(
                    new Assert\NotBlank(array('message' => 'XXXX')),
                    new Assert\Length(array('min' => 19, 'max' => 19, 'exactMessage' => 'XXX {{ limit }} XXX')))))
            ->add('xxxx', 'submit')
            ->getForm();
}

public function createModificationForm() {

    return $form = $this->createFormBuilder(null)
            ->add('modification', 'submit', array('label' => 'XXXXXXXXXXXXXXXXXXXX'))
            ->getForm();
}

My second form as only a submit button.

I passed them to my render and display them by using :

<div class="well">
    <form method="post" action='' {{form_enctype(form)}} >
        {{ form_widget(form) }}
        <input type="submit" class="btn btn-primary"/>
    </form>
    <div class='errors'>
        {{ form_errors(form) }}
     </div>
</div>

'form' is the name of my variable to the first form and 'update' for my second form.

When I attempted to submit my second form, I need to click twice and finally I get :

"This form should not contain extra fields."
And all non valid input for the remainding form.

I tried to add validation_group to false but to no avail.

I don't understand why I got this error because my forms are not embedded at all

I hope you will understand...

1
  • show the html for your second form (update) - exactly how it's rendered in the source, how you handle the form in your controller may also be useful. Commented Jun 2, 2014 at 12:31

7 Answers 7

28

You have to treat the forms separately:

if('POST' === $request->getMethod()) {
 
    if ($request->request->has('form1name')) {
        // handle the first form  
    }

    if ($request->request->has('form2name')) {
        // handle the second form  
    }
}

This is perfectly explained in Symfony2 Multiple Forms: Different From Embedded Forms (temporarily unavailable - see below)

Update

As the link provided above is temporarily unavailable, you can see an archive of that resource here.

Sign up to request clarification or add additional context in comments.

4 Comments

how to getData of each form ?
@Amine Harbaoui: If you are creating and handling the forms in the same action, you should be able to access the form data with your assigned form variable, e.g. $suiviForm->getData() . If you are handling the forms in separate actions, you have to recreate the forms, e.g. call $suiviForm = createSuiviForm();, handle the request via $suiviForm->handleRequest($request)and access then the data.
Link is broken. Any official doc by any chance? Thanks :)
You can use Web Archive until it comes back up - I've edited my answer - alternatively - go here
13

This did the trick for me in Symfony 3 (should also work for Symfony 2):

$form1 = $this->createForm(
    MyFirstFormType::class
);

$form2 = $this->createForm(
    MySecondFormType::class
);

if ($request->isMethod('POST')) {

    $form1->handleRequest($request);
    $form2->handleRequest($request);

    if ($form1->isSubmitted()) {
        // Handle $form1
    } else if ($form2->isSubmitted()) {
        // Handle $form2
    }

}

Comments

9

The problem is that you have two nameless forms (input names like inputname instead of formname[inputname], and thus when you bind the request to your form and it gets validated it detects some extra fields (the other form) and so it is invalid.

The short-term solution is to create a named builder via the form factory, so instead of:

$form = $this->createFormBuilder(null)

you should use:

$form = $this->get("form.factory")->createNamedBuilder("my_form_name")

The long term solution would be to create your own form classes, that way you can keep your form code separate from the controller.

Comments

3

The two forms will be posted.

Try using:

    $this->createNamedBuilder 

instead of

    $this->createFormBuilder

Then in your controller, locate the form by name:

if ($request->request->has("your form name") {
   $form->handleRequest($request);
}

Comments

1

This is how I handle them on my controller :

return $this->render('SgaDemandeBundle:Demande:suivi_avancement.html.twig', 
                     array('form' => $form->createView(), 
                           ........
                           'update' => $formModification->createView()));

This is the html for the second form :

<div class="well">
    <form method="post">
        <div id="form">
            <div>
                <button type="submit" id="form_modification"  
                name="form[modification]">Modification done
                </button>
            </div>
            <input type="hidden" id="form__token" name="form[_token]" 
            value="fFjgI4ecd1-W70ehmLHmGH7ZmNEHAMqXlY1WrPICtK4">
        </div>        
    </form>
</div>

This is my twig rendered :

<div class="well">
    <form method="post" {{form_enctype(update)}} >
        {{ form_widget(update) }}
    </form>
</div>

<div class="well">
    <form method="post" action='' {{form_enctype(form)}} >
        {{ form_widget(form) }}
        <input type="submit" class="btn btn-primary"/>
    </form>
     <div class='errors'>
        {{ form_errors(form) }}
     </div>
</div>

I hope this will help you.

Comments

1

Using Named forms is a viable solution for handling multiple forms, but it can get a little messy, particularly if you're generating forms dynamically.

Another method, as of Symfony 2.3, is to check which submit button was clicked.

For example, assuming that each form has a submit button named 'save':

if ('POST' == $Request->getMethod())
{
    $form1->handleRequest($Request);
    $form2->handleRequest($Request);
    $form3->handleRequest($Request);

    if ($form1->get('save')->isClicked() and $form1->isValid())
    {
        //Do stuff with form1
    }

    if ($form2->get('save')->isClicked() and $form2->isValid())
    {
        //Do stuff with form2
    }

    if ($form3->get('save')->isClicked() and $form3->isValid())
    {
        //Do stuff with form3
    }
}

I believe this has a small amount of additional overhead as compared to the named builder method (due to multiple handleRequest calls), but, in certain cases, it results in cleaner code. Always good to have multiple solutions to choose from. Some of the additional overhead could be alleviated via nested if/else statements, if necessary, but, unless we're talking about dozens of forms per page, the additional overhead is negligible in any case.

Here's an alternate implementation using anonymous functions that minimizes code repetition:

$form1Action = function ($form) use (&$aVar) {
        //Do stuff with form1
    };
$form2Action = function ($form) use (&$anotherVar) {
        //Do stuff with form2
    };
$form3Action = function ($form) use (&$yetAnotherVar) {
        //Do stuff with form3
    };
$forms = [$form1 => $form1Action, 
          $form2 => $form2Action,
          $form3 => $form3Action];

if ('POST' == $Request->getMethod())
{
    foreach ($forms as $form => $action)
    {
        $form->handleRequest($Request);
        if ($form->get('save')->isClicked() and $form->isValid())
        {
            $action($form);
        }
    }
}

Comments

-1

Look at the blockprefix :

public function getBlockPrefix()
{
    return 'app_x_form'.$form_id;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.