Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Form Validation in symfony from ajax call

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.

like image 954
Joseph Avatar asked Dec 03 '15 12:12

Joseph


3 Answers

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

like image 102
Matteo Avatar answered Nov 16 '22 17:11

Matteo


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
        }
    }
});
like image 29
SimonW Avatar answered Nov 16 '22 19:11

SimonW


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 {

                }
            }
        });
    });
like image 3
Vince Verhoeven Avatar answered Nov 16 '22 19:11

Vince Verhoeven