0
votes

I want to create a ajax form validation that verifies that form data and gives user instant feedback before really submitting the form.

For this i added a javascript function on form submit:

<form id="x" onsubmit="return dosubmit(this)" action="{{ url('/x') }}" method="POST">

<script>
    function dosubmit(form) {
        $.ajax({
            url: $(form).attr('action'),
            type: 'post',
            data: $(form).serializeArray()
        }).done(function (data) {
            form.submit();
        }).fail(function (data) {
            alert('error');
        });
        return false;
    }
</script>

And i have custom a form validator request:

class X extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required',
        ];
    }
}

When my ajax request fails everything works fine. My form validator returns the error in json and i can display it to user. The problem is that when it is successful it actually posts the data two times - first time from the ajax request and second time because i call form.submit() after ajax request is successful. Because i want to redirect the user after submit i would actually like only the second submit to reach the controller. This means i have to stop the ajax request after validation. My current workaround is that i have a line like this in my controller:

public function store(X $request)
{
    if ($request->ajax()) {
        return;
    }

    // only actual request reaches here
}

This works, but its not pretty. I don't like including this line in my controller. I would be happy if i could do something similar in my request validator, but I cant find a good way to return after validation from there. Any ideas how can i accomplish this?

2

2 Answers

0
votes

You can try it like this:

<script>
    function dosubmit(form) {
        $.ajax({
            async: false,    // make ajax not async
            url: $(form).attr('action'),
            type: 'post',
            data: $(form).serializeArray()
        }).done(function (data) {
            form.submit();
        }).fail(function (data) {
            alert('error');
        });
        return false;
    }
</script>

and in controller just do it normally without this...

if ($request->ajax()) { return; }

And please give feedback if it works...I am also interested.

0
votes

Your problem can be solved with some changed in javascript code. I think you're confused about what deferred.done() method will do. In your code, you're submitting your form twice.

Let me break down your js script, the done() method is used to do further actions after submitting your form (Please refer).

In your code, the first $.ajax actually submits your form to backend (here, if there are any errors from backend you can handle them in fail section). If the form submits successfully without any errors, then in done section you can define functions or actions about what you want to do after a successful form submission.

Instead of defining what to do after a successful form submission, you are resubmitting the same form again. So remove that part from js code and also the workaround you've done in your backend.

function dosubmit(form) {
    $.ajax({
        url: $(form).attr('action'),
        type: 'post',
        data: $(form).serializeArray()
    }).done(function (data) {
        // form.submit();
        // handle successful form submission
    }).fail(function (data) {
        alert('error');
    });
    return false;
}