15

I need to store data from a form with symfony through an ajax call me not to update the browser. Also I need you in case of errors in the fields can somehow get them in response to that call Ajax and to show my form errors, all without refreshing the page.

I have a form with symfony asset to validate fields, and make everything perfect if ajax call is performed, stores the data or updates the page showing errors, but I need that same without refreshing the page.

Then I put some of the code I'm using:

Controller:

public function createAction(Request $request)
{
    $entity = new Student();
    $form = $this->createCreateForm($entity);
    $form->handleRequest($request);

    if ($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($entity);
        $em->flush();

        return $this->redirect($this->generateUrl('student_show', array('id' => $entity->getId())));
    }

    return $this->render('BackendBundle:Student:new.html.twig', array(
        'entity' => $entity,
        'form'   => $form->createView(),
    ));
}

ajax call:(I do not understand how to handle the error part)

$('.form_student').submit(function(event) {
   event.preventDefault();

  $.ajax({
    type: 'POST',
    url: Routing.generate('student_create'),
    data: $(this).serialize(),

    success: function(data) {

      //clean form
      cleanForm($(this));

      //show success message
      $('#result').html("<div id='message'></div>");
      $('#message').html("<h2> student created</h2>").hide();
      $('#message').fadeIn('slow').delay(5000).fadeOut('slow');
      event.stopPropagation();   
    },
    error: function (xhr, desc, err) 
      {
        alert("error");
      }
    })
  return false;
});

I've seen some return a JsonResponse from the controller and use Ajax, but I'm starting with Ajax and I do not know how to use it. Then I put the code I mean:

 if ( $request->isXmlHttpRequest() ) {

    if ($form->isValid()) {
     //...
     return new JsonResponse(array('message' => 'Success!'), 200);
    }

    $response = new JsonResponse(array(
    'message' => 'Error',
    'form' => $this->renderView('BackendBundle:student:new.html.twig',
            array(
        'entity' => $entity,
        'form' => $form->createView(),
    ))), 400);

  return $response;
}

If you could help me understand more how to use Ajax to solve this problem, I eternally grateful, because for many manuals I've seen I still do not understand it well.

Thank you very much in advance.

3 Answers 3

21

I can share with you a custom solution i use in an old project for manage error on form submitted via ajax call.

In the controller action:

 ....
 if ( $request->isXmlHttpRequest() ) {

        if (!$form->isValid()) {
                return array(
            'result' => 0,
            'message' => 'Invalid form',
            'data' => $this->getErrorMessages($form)
        );

            // Do some stuff
           return array(
            'result' => 1,
            'message' => 'ok',
            'data' => ''
         }

}
    // Generate an array contains a key -> value with the errors where the key is the name of the form field
    protected function getErrorMessages(\Symfony\Component\Form\Form $form) 
    {
        $errors = array();

        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }

        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }

        return $errors;
    }

And the js code is something like: In the client side:

        $.ajax({
            url: ...,
            data: ....,
            type: "POST",
            success: function(data) {
                if(data.result == 0) {
                    for (var key in data.data) {
                        $(form.find('[name*="'+key+'"]')[0]).before('<ul class="errors"><li>'+data.data[key]+'</li></ul>');
                    }
                } else {
                // Submit OK
                }
            }
        });

hope this help

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

9 Comments

Hi @Matteo, Thank you very much again for the code, it has worked perfectly getting errors in the ajax call, but I have a problem on my form I have another embedded code form and it did not return the fields with errors that embedded form. Would you know how I could add it to the key date of the array that is returned in the call?I show the two fields of the form Estudent which has another embedded form Responsible (parents) in this way: ->add('responsiblee1', new PadresType(),array('label' => 'Mother')) ->add('responsible2', new PadresType(),array('label' => 'Father'))
I have read some need to add cascade_validation=true for the validation of the embedded form is made, but would not know where to place. Could it be that what I need to validate it?
Hi @Matteo, can you help me? I can not solve my problem validate the embedded form
Hi @Joseph, I don't know if my solution can adapt to your needed. Try investigate in the getErrorMessages how it handle the subform situation and how apply it to the js error management. Sorry but i don't have this needed in my project....
@Matteo , thank you it works good. I'd like to fetch errors in a separate view errors.html.twig and return it in the JsonResponse. I can do that an display the view with jquery but can't understand how to change this javascript loop for (var key in data.data) { $(form.find('[name*="'+key+'"]')[0]).before('<ul class="errors"><li>'+data.data[key]+'</li></ul>'); } to twig code. I tried this but doesn't work {% for error in data %} {{ error }} {% endfor %}
|
9

There is actually a much easier way to render form validation errors when submitting a form via ajax. Both the answers above require you to manually attach the error messages to the right fields, etc.

Since the question is old, I will generalize a bit from your specific case for those who come here with a similar problem:

In the controller, you can just return the rendered form if it does not validate:

public function createAction(Request $request)
{
    $form = $this->createForm(StudentType::class);
    $form->handleRequest($request);

    if ($form->isSubmitted() && !$form->isValid()) {
        return $this->render('new.html.twig', [
            'form' => $form->createView(),
        ]);
    }
    // ...
}

Then in your ajax call, you can take the html that gets returned (including any validation error messages) and plug it back into your form. Below I replace just the contents of the form, so any handlers attached to the form itself stay intact.

$.ajax({
    url: ...,
    data: ....,
    type: "POST",
    success: function(data) {
        if(!data.success) { // undefined here, set to true in controller the form is valid
            var innerHTML = $(data).find('#appbundle_student').html();
            $('#appbundle_student').html(innerHTML);
        } else {
            // Submit OK
        }
    }
});

2 Comments

nice trick, but how do you add this data.success in the controller?
You can add a "success" item to the JSON array you return in your controller, but it doesn't really matter. You can also use "result" like in the top answer. It's just to determine if you need to display validation errors.
3

With symfony 3 and the error validator you can parse your Ajax request like this:

 /**
     * Create new student (ajax call)
     * @Method("POST")
     * @Route("/student/create", name"student_create")
     * @param Request $request
     * @return JsonResponse
     */
    public function createAction(Request $request)
    {

        $student = new Student();
        $form = $this->createForm(CreateStudentType::class, $student);
        $form->handleRequest($request);
        $errors = array();

        if ($form->isSubmitted()) {
            $validator = $this->get('validator');
            $errorsValidator = $validator->validate($student);

            foreach ($errorsValidator as $error) {
                array_push($errors, $error->getMessage());
            }


            if (count($errors) == 0) {
                $em = $this->getDoctrine()->getManager();
                $em->persist($student);
                $em->flush();

                return new JsonResponse(array(
                    'code' => 200,
                    'message' => 'student toegevoegd',
                    'errors' => array('errors' => array(''))),
                    200);
            }

        }

        return new JsonResponse(array(
            'code' => 400,
            'message' => 'error',
            'errors' => array('errors' => $errors)),
            400);
    }

And jquery ajax

$("#createForm").submit(function(e) {

        e.preventDefault();
        var formSerialize = $(this).serialize();

        var url = location.origin + '/web/app_dev.php/student/create';
        $.ajax({
            type: "POST",
            url: url,
            data: formSerialize,
            success: function (result) {
                console.log(result);
                if (result.code === 200) {
                    // refresh current url to see student
                } else {

                }
            }
        });
    });

1 Comment

you're validating the form twice here, handleRequest already validates the form if it is submitted. You can use $form->getErrors()

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.