6

On certain pages I use forms within bootstrap modals. I submit the form with Ajax and it gets validated in the controller. The most users will fill in the form correctly but if a validation fails the form is re-rendered and got send back to the user. I don't like this at all, but I can't find a better way because I can't get access the validation errors of the fields. Does someone has a better approach to achieve validation errors send back in JSON?

3
  • You can make a validation in JS, but imho taht's better approach to do server side validation. Snding data via JSON is a good choice. What is wrong with this approach ? Commented Dec 4, 2013 at 14:17
  • 1
    No, I don't use JS validation because I don't want to define validations on two seperate places. I do server side validation at the moment but I can't find a decent way to get all errors from the form + entity properties and validators. Commented Dec 4, 2013 at 14:33
  • Just interate over elements from the form, and get errors of each. Commented Dec 4, 2013 at 14:44

4 Answers 4

3

I created a function myself

public function getFormErrors(Form $form) {
    $errors = $form->getErrors();
    foreach ($form->all() as $child) {
        foreach ($child->getErrors() as $key => $error) {
            $template = $error->getMessageTemplate();
            $parameters = $error->getMessageParameters();

            foreach ($parameters as $var => $value) {
                $template = str_replace($var, $value, $template);
            }

            $errors[$child->getName()][] = $template;
        }
    }
    return $errors;
}
Sign up to request clarification or add additional context in comments.

Comments

2

if I understand right you have a form and you need to get the errors for each field separately. if so, have a look at \Symfony\Component\Form\Form::getErrorsAsString() & do smth of the kind:

function getFormErrors($form)
{
    $errors = array();

    // get the form errors
    foreach($form->getErrors() as $err)
    {
        // check if form is a root
        if($form->isRoot())
            $errors['__GLOBAL__'][] = $err->getMessage();
        else
            $errors[] = $err->getMessage();
    }

    // check if form has any children
    if($form->count() > 0)
    {
        // get errors from form child
        foreach ($form->getIterator() as $key => $child)
        {
            if($child_err = getFormErrors($child))
                $errors[$key] = $child_err;
        }
    }

    return $errors;
}

1 Comment

Awesome! Could you explain please why do you need to check if form is a root?
2

I'd say that the cleanest solution is to implement JMSSerializerBundle (http://jmsyst.com/bundles/JMSSerializerBundle) which uses the following Class:

https://github.com/schmittjoh/serializer/blob/6bfebdcb21eb0e1eb04aa87a68e0b706193b1e2b/src/JMS/Serializer/Handler/FormErrorHandler.php

then in your controller:

        // ...
        if ($request->isXMLHttpRequest()) {
        $jsonResponse = new JsonResponse();

        $serializer = $this->container->get('jms_serializer');
        $form = $serializer->serialize($form, 'json');

        $data = array('success' => false,
                       'errorList' => $form);

        $jsonResponse->setData($data);

        return $jsonResponse;
    }

2 Comments

Really clean approach. Should be the answer.
Not so clean IMO, because you have to parse JSON contained in the errorList field of the response. It means you have to JSON.parse a string that is contained in a JSON reponse...
1

I just have the same problem Today !

I sent the form with ajax, and if my controller sent me not a json 'OK', the form is refresh with the new form sent by the controller, who contains errors. Data 'OK' is sent when form->isValid(), else it return the form render.

HTML :

<div class="form_area">
     <form id="myform" action.... >
           ...code form ...
     </form>
</div>

Controller Action:

use Symfony\Component\HttpFoundation\JsonResponse;

public function myEditAction(){
    .......
    if ( $request->getMethod() == 'POST' ) {
        $form->bind($request);

        if ($form->isValid()) {
            ... code whn valide ...
            if ( $request->isXmlHttpRequest() ) {
                return new JsonResponse('OK');
            }
        }
    }

    return $form;
}

JS:

$('#myform').on('submit',function(e){
            var formdata = $('#myform').serialize();
            var href = $(this).attr('action');
            $.ajax({
                type: "POST",
                url: href,
                data: formdata,
                cache: false,
                success: function(data){
                    if(data != "OK") {
                        $('.form_area').html(data);
                    } 
                },
                error: function(){},
                complete: function(){}
            });
            return false;
        });

1 Comment

That's a solution I don't like. It's just nasty and not practical. See my own answer in how I solved the issue.

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.