3
votes

Hi I am really having a hard time on the new structures in laravel 5, I'm trying to submit a form via AJAX post but I keep getting error 422 (Bad Request). Am I missing something or do I need to do something with my Request class? Here is my code:

Controller:

public function login(LoginRequest $request)
{

    if ($this->auth->attempt($request->only('email', 'password')))
    {
        return redirect("/");
    }

    return response()->json(['errors'=>$request->response]);
}

LoginRequest file (I added a custom response method which is):

public function response(array $errors)
{
    if ($this->ajax() || $this->wantsJson())
    {
        return response()->json($errors, 422);
    }

    return response()->json($errors);
}

My ajax code:

$("#form-login").submit(function(){

  var selector = $(this);
  $.ajax({
     url: selector.attr("action"),
     type: "post",
     data: selector.serialize(),
     dataType: "json",
  }).done(function(data){
     console.log(data);
     if(data.status == "failed"){
       alert("error");
     }else{
        alert("success");
     }
  });

  return false;
});

So My problem is that when I submit my form all I can see from my console is - Failed to load resource: the server responded with a status of 422 (Bad Request)

Please if anyone can help. Thanks in advance!

2
You are missing code for the question, without it, we can not really help you. - user4469467
Can you take a look at app/storage/logs/laravel.log and post the error message? I suppose it's a TokenMismatchException... - lukasgeiter
It's working now. thanks for the time :) - user4269033

2 Answers

6
votes

I had a similar problem, I'll leave here the code that I ended up with.

the form:

<div class="container">
        <div class="text-center">
            <div class="title">{!!HTML::image("img/HERLOPS_Transparent_Blue.png") !!}</div>
            {!! Form::open(['data-remote','url' => '/auth/login', 'class'  => 'col-lg-4 col-lg-offset-4', 'id' => 'login_form']) !!}

                <div class="form-group">
                    <input type="email" class="form-control" id="email" name="email" placeholder="Your Email" value="{{ old('email') }}">
                </div>
                <div class="form-group">
                    <input type="password" class="form-control" id="password" name="password" placeholder="Your Password">
                </div>
                <button id="submit" type="submit" class="btn btn-primary">Login <i class="fa fa-sign-in"></i></button>
                <div style="clear:both">
                    <a class="btn btn-link" href="{{ url('/password/email') }}">Forgot Your Password?</a>
                </div>

            {!! Form::close() !!}
            <div style="text-align:center" class="col-lg-4 col-lg-offset-4" id="form-errors"></div>
            <div style="clear:both"></div>
            <div class="quote">{{ Inspiring::quote() }}</div>
        </div>
    </div>

The jquery:

(function() {
var submitAjaxRequest = function(e) {

    var form = $(this);

    var method = form.find('input[name="_method"]').val() ||  'POST'; //Laravel Form::open() creates an input with name _method

    $.ajax({

        type: method,

        url: form.prop('action'),

        data: form.serialize(),

        success: function(NULL, NULL, jqXHR) {
            if(jqXHR.status === 200 ) {//redirect if  authenticated user.
                $( location ).prop( 'pathname', 'projects' );
                console.log(data);
            }
        },
        error: function(data) {
            if( data.status === 401 ) {//redirect if not authenticated user
                $( location ).prop( 'pathname', 'auth/login' );
                var errors = data.responseJSON.msg;
                errorsHtml = '<div class="alert alert-danger">'+errors+'</div>';
                $( '#form-errors' ).html( errorsHtml ); 
            }
            if( data.status === 422 ) {
            //process validation errors here.
            var errors = data.responseJSON; 

            errorsHtml = '<div class="alert alert-danger"><ul>';

            $.each( errors , function( key, value ) {
                errorsHtml += '<li>' + value[0] + '</li>'; 
            });
            errorsHtml += '</ul></di>';

            $( '#form-errors' ).html( errorsHtml ); 
            } else {

            }
        }
    });

    e.preventDefault();
};

$('form[data-remote]').on('submit', submitAjaxRequest);
})();

And finally the method of the controller that handles the ajax login request,

/**
 * Handle an ajax login request to the application
 * 
 * @param \Illuminate\Http\Request $request
 * @param \Illuminate\Http\Response
 */ 
public function postLogin(Request $request)
{
    $this->validate($request, [
        'email' => 'required|email', 'password' => 'required',
    ]);// Returns response with validation errors if any, and 422 Status Code (Unprocessable Entity)

    $credentials = $request->only('email', 'password');

    if ($this->auth->attempt($credentials))
    {
        return response(['msg' => 'Login Successfull'], 200) // 200 Status Code: Standard response for successful HTTP request
          ->header('Content-Type', 'application/json');
    }

    return response(['msg' => $this->getFailedLoginMessage()], 401) // 401 Status Code: Forbidden, needs authentication
          ->header('Content-Type', 'application/json');

}
1
votes

I was actually just struggling with this myself, and the answer is pretty simple actually.

Because Laravel's request responds with a status code of 422, jQuery's success/done functions don't fire, but rather the error function, seeing as it's not 200.

So, in order to get the JSON response from your AJAX request generated from the Request object due to validation failing, you need to define the error handler, in your case as follows:

$.ajax({ /* ... */ })
    .done(function(response) { /* ... */ })
    .error(function(data) { // the data parameter here is a jqXHR instance
        var errors = data.responseJSON;
        console.log('server errors',errors);
    });