2
votes

I have a form on my page. After submission I am adding additional data to the form for submission. I can submit the serialized form data via ajax, however, I am unable to successfully process the response. The response is coming from Laravel and includes a redirect URL, a Session 'success' or 'error' message, and possible form data on a form error redirect.

JS submit function

function submit() {
    var formData = $('#form').serializeArray();
    formData.push({ name: "additional_data", value: additional_data });
    $.ajax({
        type: "POST",
        url: "/submit_form_data",
        data: formData,
        success: function(data) {
            // response includes redirect url, session data ('success' or 'error' + message), form data (if form error)
        }
    });
}

Laravel data submission route

public function submitData(Request $request) {
    $data = $request->all();

    // check for form error and redirect back with error message and form input
    $validator = Validator::make($data);
    if ($validator->fails()) {
        return redirect()
            ->back()
            ->withErrors($validator)
            ->withInput();
    }

    // submit data and redirect with success message
    $this->createEntry($data);
    return redirect('/dashboard')
      ->with('success', "Data successfully submitted");
}

I have tried submitting the data via XMLHttpRequest, but the form data and session data do not seem to be contained anywhere within the request response.

function submit() {
    var formData = $('#form').serializeArray();
    formData.push({ name: "additional_data", value: additional_data });
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
        if (request.readyState == XMLHttpRequest.DONE) {
            // window redirects, but form data and session data are lost
            window.location.replace(request.responseURL);
        }
    }
    request.open("POST", '/submit_form_data');
    request.send(formData);
}

If I submit the form via a simple $("#form").submit(), the form data and session data are all transferred intact, however, there does not seem to be any way to append form data when using this method and so my "additional_data" is lost.

And one final point. If I redirect without waiting for XMLHttpRequest.DONE, the form and session data is retained. However, in this case I have no idea which URL I should be redirecting to.

function submit() {
    var formData = $('#form').serializeArray();
    formData.push({ name: "additional_data", value: additional_data });
    var request = new XMLHttpRequest();
    request.open("POST", '/submit_form_data');
    request.send(formData);
    // session data will be intact, but I don't have a redirect URL
    window.location.replace('/dashboard');
}

UPDATE:

Using the suggestion from hppycoder, I was able to find a somewhat workable solution.

The problem is that the values required on the frontend need to be set via PHP. This includes the $errors variable, which is set via redirect()->withErrors($validator), and the form input data which is set via redirect()->withInput().

However, I need to be able to read the php response in my JavaScript. I can do this if I return a response()->json() object, but then the $errors and form input data would not be set.

The workaround is to combine the two approaches, although it feels less than elegant, as it requires that I make multiple calls to my POST method.

Laravel submit route

public function submitData(Request $request) {
    $data = $request->all();

    // check for form error and redirect back with error message and form input
    $validator = Validator::make($data);
    if ($validator->fails()) {
        // this will set the necessary php values ($errors variable and form input data)
        // response cannot be read by ajax
        return redirect()
            ->back()
            ->withErrors($validator)
            ->withInput();
    }

    // no form errors, submit data and return 'success' response
    $this->createEntry($data);
    // this response can be read by ajax, and the Session 'success' value is set
    Session::put('success', ("Data successfully submitted"));
    return response()->json([
        'success' => true
    ]);
}

JavaScript submit function

function submit() {
    var formData = $('#form').serializeArray();
    formData.push({ name: "additional_data", value: additional_data });
    $.ajax({
        type: "POST",
        url: "/submit_form_data",
        data: formData,
        success: function(data) {
            if (data.success) {
                // check for 'success' and redirect to dashboard
                window.location.replace("/dashboard");
            } else {
                // if no success message, reload current page with form errors and data
                // if I call window.location.reload() here, the form data and $errors variable are not set
                // in order to set these I need to submit the data a second time via XMLHttpRequest
                var form = document.getElementById('form');
                var formData = new FormData(form);
                formData.push({ name: "additional_data", value: additional_data });
                var request = new XMLHttpRequest();
                request.open("POST", '/submit_form_data');
                request.send(formData);
                // now after reload, the form data and $errors varaible will be set
                window.location.reload();
            }
        }
    });
}

Additionally, below is my html, which shows how the php values are being rendered by the blade template. I should have included this in the original post to clarify why I needed the php values to be set.

<body>

    @if (count($errors->all()) > 0)
        <div class="alert alert-danger alert-block">
            <button type="button" class="close" data-dismiss="alert">&times;</button>
            <h4>Error</h4>
            Please check the form below for errors
        </div>
    @endif

    @if ($message = Session::get('success'))
        <div class="alert alert-success alert-block">
            <button type="button" class="close" data-dismiss="alert">&times;</button>
            <h4>Success</h4>
            {{ $message }}
        </div>
    @endif

    <form id="form" class="form-horizontal" role="form" method="POST" enctype="multipart/form-data">

        <div class="row form-group">
            <label class="control-label">Some Data</label>
            <input class="form-control" name="some_data" value="{{ old('some_data') }}">
        </div>

        <div class="row">
            @if ($errors->has('some_data'))
                <span class="help-block">
                    <strong>{{ $errors->first('some_data') }}</strong>
                </span>
            @endif
        </div>

    </form>

</body>
1
You are telling Laravel to return a redirect('/dashboard') which will redirect the browser to the dashboard. What you want to do instead is have another endpoint which returns JSON instead. That's why you have a redirect URL and a success messagehppycoder
@hppycoder I think that makes sense to me. However, which submission method should be using, ajax or XMLHttpRequest, or does it not matter?brassmookie
The request could use either jQuery or XMLHttpRequest, the Laravel response is what is important. The HTTP Responses documentation should help you solve the issuehppycoder

1 Answers

0
votes

I'm going to use the documentation I posted earlier to show.

public function submitData(Request $request) {
    $data = $request->all();

    // check for form error and redirect back with error message and form input
    $validator = Validator::make($data);
    if ($validator->fails()) {
        return redirect()
            ->back()
            ->withErrors($validator)
            ->withInput();
    }

    // submit data and redirect with success message
    $this->createEntry($data);
    return response()->json([
        'success' => true,
        'message' => 'Data successfully submitted',
    ]);
}

JS Submit:

function submit() {
    var formData = $('#form').serializeArray();
    formData.push({ name: "additional_data", value: additional_data });
    $.ajax({
        type: "POST",
        url: "/submit_form_data",
        data: formData,
        success: function(data) {
            console.log(data);
            // response includes redirect url, session data ('success' or 'error' + message), form data (if form error)
        }
    });
}