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">×</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">×</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>
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 message – hppycoder