No error messages from 422 response on laravel form request from vue component - laravel

I'm trying to submit a form request using axios, have it validated, and return errors if the validation fails. The problem is, when I submit the form, no error messages are returned for me to show on the client side. Here's the HTTP request and vue component:
<div class="card">
<div class="card-header">
<h4>Information</h4>
</div>
<div class="card-body">
<p v-if='!isEditMode'><strong>Name:</strong> {{businessData.name}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-name">Name</label></strong>
<input class="form-control" name="business-name" v-model='businessData.name'>
</div>
<p v-if='!isEditMode'><strong>Description:</strong> {{businessData.description}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-description">Description</label></strong>
<textarea class="form-control normal" name="business-description"
placeholder="Enter your services, what you sell, and why your business is awesome"
v-model='businessData.description'></textarea>
</div>
</div>
</div>
<div class="card">
<h4 class="card-header">Address Information</h4>
<div class="card-body">
<p v-if="!isEditMode"><strong>Street Address: </strong> {{businessData.street}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-street">Street Address: </label></strong>
<input type="text" class="form-control" name="business-street" v-model='businessData.street' placeholder="1404 e. Local Food Ave">
</div>
<p v-if="!isEditMode"><strong>City: </strong> {{businessData.city}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-city">City: </label></strong>
<input class="form-control" type="text" name="business-city" v-model='businessData.city'>
</div>
<p v-if="!isEditMode"><strong>State: </strong> {{businessData.state}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-state">State: </label></strong>
<select class="form-control" name="business-state" id="state" v-model="businessData.state" >...</select>
</div>
<p v-if="!isEditMode"><strong>Zip: </strong> {{businessData.zip}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-zip">Zip: </label></strong>
<input class="form-control" type="text" maxlength="5" name="business-zip" v-model='businessData.zip'>
</div>
</div>
</div>
<div class="card">
<h4 class="card-header">Contact Information</h4>
<div class="card-body">
<p v-if="!isEditMode"><strong>Phone: </strong> {{businessData.phone}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-phone">Phone: </label></strong>
<input class="form-control" type="tel" name="business-phone" v-model='businessData.phone'>
</div>
<p v-if="!isEditMode"><strong>Email: </strong> {{businessData.email}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-Email">Email: </label></strong>
<input class="form-control" type="email" name="business-email" v-model='businessData.email'>
</div>
</div>
</div>
</div>
<script>
export default {
data () {
return {
isEditMode: false,
businessData: this.business,
userData: this.user,
errors: []
}
},
props: {
business: {},
user: {},
role: {}
},
//Todo - Institute client side validation that prevents submission of faulty data
methods: {
validateData(data) {
},
saveBusinessEdits () {
axios.put('/businesses/' + this.business.id , {updates: this.businessData})
.then(response => {
console.log(response.data)
// this.businessData = response.data;
this.isEditMode = false;
})
.catch (response => {
console.log(response.data)
this.isEditMode = false;
})
},
saveUserEdits () {
axios.put('/profile/' + this.user.id , {updates: this.userData})
.then(response => {
console.log(response.data)
this.userData = response.data;
this.isEditMode = false;
})
.catch (response => {
console.log(response)
this.isEditMode = false;
})
}
}
}
Route
Route::put('/businesses/{id}', 'BusinessesController#update');
BusinessController and update function
public function update(BusinessRequest $request, $id)
{
$business = Business::find($id)->update($request->updates);
$coordinates = GoogleMaps::geocodeAddress($business->street,$business->city,$business->state,$business->zip);
if ($coordinates['lat']) {
$business['latitude'] = $coordinates['lat'];
$business['longitude'] = $coordinates['lng'];
$business->save();
return response()->json($business,200);
} else {
return response()->json('invalid_address',406);
}
$business->save();
return response()->json($business,200);
}
and BusinessRequest class
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'business-name'=> 'required|string|max:255',
'business-description'=> 'required|string',
'business-phone' => 'nullable|phone|numeric',
'business-email' => 'nullable|email',
'business-street'=> 'required|string',
'business-city' => 'required|string',
'business-state' => 'required|string|max:2',
'business-zip' => 'required|min:5|max:5|numeric',
];
}
public function messages() {
return [
'business-zip.min:5' =>'your zip code must be a 5 characters long',
'business-email.email'=>'your email is invalid',
'business-phone.numeric'=>'your phone number is invalid',
];
}
}
I don't understand why, even if input valid data, it responds with a 422 response and absolutely no error messages. Since this is laravel 5.6, the 'web' middleware is automatic in all of the routes in the web.php file. So this isn't the problem. Could anyone help me normalize the validation behavior?

In Laravel a 422 status code means that the form validation has failed.
With axios, the objects that are passed to the then and catch methods are actually different. To see the response of the error you would actually need to have something like:
.catch (error => {
console.log(error.response)
this.isEditMode = false;
})
And then to get the errors (depending on your Laravel version) you would have something like:
console.log(error.response.data.errors)
Going forward it might be worth having a look at Spatie's form-backend-validation package

You can use Vue.js and axios to validate and display the errors. Have a route called /validate-data in a controller to validate the data.
app.js file:
import Vue from 'vue'
window.Vue = require('vue');
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
class Errors {
constructor() {
this.errors = {};
}
get(field) {
if (this.errors[field]) {
return this.errors[field][0];
}
}
record(errors) {
this.errors = errors;
}
clear(field) {
delete this.errors[field];
}
has(field) {
return this.errors.hasOwnProperty(field);
}
any() {
return Object.keys(this.errors).length > 0;
}
}
new Vue({
el: '#app',
data:{
errors: new Errors(),
model: {
business-name: '',
business-description: '',
business-phone: ''
},
},
methods: {
onComplete: function(){
axios.post('/validate-data', this.$data.model)
// .then(this.onSuccess)
.catch(error => this.errors.record(error.response.data.errors));
},
}
});
Make a route called /validate-data with a method in the controller, do a standard validate
$this->validate(request(), [
'business-name'=> 'required|string|max:255',
'business-description'=> 'required|string',
'business-phone' => 'nullable|phone|numeric',
'business-email' => 'nullable|email',
'business-street'=> 'required|string',
'business-city' => 'required|string',
'business-state' => 'required|string|max:2',
'business-zip' => 'required|min:5|max:5|numeric'
]
);
Then create your inputs in your view file, using v-model that corresponds to the vue.js data model fields. Underneath it, add a span with an error class (basic red error styling, for example) that only shows up if the errors exist. For example:
<input type="text" name="business-name" v-model="model.business-name" class="input">
<span class="error-text" v-if="errors.has('business-name')" v-text="errors.get('business-name')"></span>
Don't forget to include the app.js file in footer of your view file. Remember to include the tag, and run npm run watch to compile the vue code. This will allow you to validate all errors underneath their input fields.
Forgot to add, have a buttton that has #onclick="onComplete" to run the validate method.

Related

Uncaught (in promise) csrf Vue js laravel

i am creating the login form in vuejs.i tested through postman api working well. when i check with vue js validtaion it is not working.login Error,Uncaught (in promise) csrf Vue js laravel.
what i tried so far i attached below.i think the json validation problem can you check it.i attached the full source code below.
Login.vue
<template>
<div class="row">
<div class="col-sm-4" >
<h2 align="center"> Login</h2>
<form #submit.prevent="LoginData">
<input type="hidden" name="_token" :value="csrf">
<div class="form-group" align="left">
<label>Email</label>
<input type="email" v-model="student.email" class="form-control" placeholder="Mobile">
</div>
<div class="form-group" align="left">
<label>Password</label>
<input type="password" v-model="student.password" class="form-control" placeholder="Mobile">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import axios from 'axios';
Vue.use(axios)
export default {
name: 'Registation',
data () {
return {
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
result: {},
student:{
email: '',
password: ''
}
}
},
created() {
},
mounted() {
console.log("mounted() called.......");
},
methods: {
LoginData()
{
axios.post("http://127.0.0.1:8000/api/login", this.student)
.then(
({data})=>{
console.log(data);
try {
if (data === true) {
alert("Login Successfully");
this.$router.push({ name: 'HelloWorld' })
} else {
alert("Login failed")
}
} catch (err) {
alert("Error, please try again");
}
}
)
}
}
}
</script>
LoginController
public function check(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials))
{
return response()->json(['data' => true ]);
}
return response()->json(['data' => 'Fail']);
}
}
According to Laravel 9 docs you have to send csrf token. Here's the link that talk about it:
https://laravel.com/docs/9.x/sanctum#csrf-protection

"TypeError: Cannot read property 'title' of undefined" in form

An error is returned when I try to post the form.
The form is in a component, and the same structure is used in another component but does not generate any error.
I tried to find the mistake by myself but impossible to find the solution.
<template>
<div class="card" style="width: 18rem;margin:0 0 1rem 1rem;">
<div class="card-body">
<h4 class="mt-3 text-center" style="cursor:pointer;" #click="show=!show" >Add list</h4>
<form v-show="show" #submit.prevent="submitList">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" :class="{'is-invalid':errors.title}" v-model="form.title"/>
<p class="text-danger" v-if="errors.title" v-text="errors.title[0]"></p>
</div>
<button type="submit" class="btn btn-lg btn-success mb-4">Submit</button>
</form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
show : false,
form: {
title: '',
},
errors: {}
}
},
methods: {
submitList() {
axios.post('/list', this.form)
.then(({data}) => {
this.$emit('newList', data),
this.form.title = '',
this.show = false,
this.errors = {}
})
.catch(error => {
this.errors = error.response.data.errors
})
}
}
}
</script>
Error in render: "TypeError: Cannot read property 'title' of undefined"
Reference this at the start of the method submitList and then use the reference in the axios response.
let that = this;
then that.form.title;
submitList () {
let that = this;
axios.post('/list', this.form)
.then(({ data }) => {
that.$emit('newList', data),
that.form.title = '',
that.show = false,
that.errors = {}
})
.catch(error => {
that.errors = error.response.data.errors
})
}
There's not really enough information here to answer the question. Since it's a render issue my guess is that it's one of these lines:
<input type="text" class="form-control" :class="{'is-invalid':errors.title}" v-model="form.title"/>
<p class="text-danger" v-if="errors.title" v-text="errors.title[0]"></p>
The question is what you get from the backend in your catch method. You should probably log that value and check that it's formated the way you think it is.
A nice tool for debugging Vue is the browser extension, maybe it will help with clearing up the problem.
If this does not solve your problem you need to provide more info:
When does the error occur
What is the value of the data-properties when it occurs
Maybe a screenshot of a more thorough error-message

Getting a vue form to go to the next page after submit in laravel

I'm using both laravel and vue and I'm trying to get my vue form to go to another page when I've submitted, but the problem is that once it's submitted it refreshes and goes back to the page it's on instead of the other page.
When I check my network tab in the dev tools, it posted to the right page but it doesn't show up in the browser
This is my vue
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an Supplier Code Selection component.
<br>
<form #submit.prevent="submit">
<label for="parent-product">Parent Product</label>
<select name="parent-product" id="parent-product" class="form-control" v-model="selected_parent">
<option>Please select your code</option>
<option v-for="product in products" :value="product.id">
{{ product.supplier_code }}
</option>
<option v-for="child in children" :value="child.id">
{{ child.supplier_code }}
</option>
</select>
<input type="submit" class="btn btn-primary" value="Submit">
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: [
'products',
'children',
'selected_parent'
],
mounted() {
console.log('Component mounted.')
},
methods: {
submit(){
var formData = new FormData();
console.log('this is the select box - '+this.selected_parent);
formData.append('parent-product', this.selected_parent);
return axios.post('/add-to-cart/'+this.selected_parent, formData);
},
},
}
</script>
My route
Route::any('/add-to-cart/{id}', 'PublicController#getAddToCart')->name('product.addToCart');
My controller function
public function getAddToCart(Request $request, $id)
{
$menus_child = Menu::where('menu_id', 0)->with('menusP')->get();
$contacts = Contact::all();
$product = Product::find($id);
$supplier_code = $request->supplier_code;
$oldCart = Session::has('cart') ? Session::get('cart') : null;
$cart = new Cart($oldCart);
$cart->add($product, $product->id, $supplier_code);
$request->session()->put('cart', $cart);
return view('public.shopping-cart', ['products' => $cart->items, 'totalPrice' => $cart->totalPrice, 'menus_child' => $menus_child, 'contacts' => $contacts, 'supplier_code' => $supplier_code]);
}
You could just add a location if the axios call returns success. Ps. untested code.
methods: {
submit(){
var formData = new FormData();
console.log('this is the select box - '+this.selected_parent);
formData.append('parent-product', this.selected_parent);
return axios.post('/add-to-cart/'+this.selected_parent, formData)
.then(response => { location: '/'});
},
I found my issue. I forgot to change
return view('public.shopping-cart', compact('supplier_code'));
to
return ['redirect' => route('product.shoppingCart')];
in my laravel controller function

Laravel 5.5 Multilanguage validation

Please tell me, I ran into a problem. There is a site based on Laravel 5.5. The site has a multilanguage (two languages en/ru). For multilanguage I'm using:
dimsav/laravel-translatable
mcamara/laravel-localization
Added language files to the directory resources/lang/ru. The problem is the validation of the form. The site has a feedback form in the modal window, working with ajax (sending and validating), error messages are displayed only in the default language, the default language is en. I tried to send data from the form without the help of ajax, everything works well, messages are displayed in both Russian and English.
reoutes/web.php
Route::group(['prefix' => LaravelLocalization::setLocale()], function(){
Route::get('/', 'PagesController#getProfile')->name('profile');
Route::get('/skills', 'PagesController#getSkills')->name('skills');
Route::get('/portfolio', 'PagesController#getPortfolio')->name('portfolio');
Route::get('/resume', 'PagesController#getResume')->name('resume');
Route::post('/contact', 'PagesController#contact');
});
controller
public function contact(Request $request){
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'message' => 'required'
]);
if ($validator->passes()) {
Mail::to('mycontactform#mail.ru')->send(new Contact($request));
return response()->json(['success'=>'Message sent successfully!']);
}
return response()->json(['error'=>$validator->errors()->all()]);
}
js
$(document).ready(function() {
$(".btn-send-message").click(function(e){
e.preventDefault();
$.ajax({
url: "/contact",
type:'POST',
data: $('#contact-form').serialize(),
beforeSend: function() {
$("#loading").show();
$(".fa-paper-plane").hide();
},
complete: function() {
$("#loading").hide();
$(".fa-paper-plane").show();
},
success: function(data) {
if($.isEmptyObject(data.error)){
printSuccessMsg();
}else{
printErrorMsg(data.error);
}
}
});
});
var $success_msg = $(".print-success-msg");
var $error_msg = $(".print-error-msg");
function printSuccessMsg() {
$success_msg.html('Message sent successfully!');
$success_msg.css('display','block');
$success_msg.delay(5000).fadeOut(350);
$('#contact-form')[0].reset();
}
function printErrorMsg (msg) {
$error_msg.find("ul").html('');
$error_msg.css('display','block');
$.each( msg, function( key, value ) {
$error_msg.find("ul").append('<li>'+value+'</li>');
});
$error_msg.delay(5000).fadeOut(350);
}
});
form
<div class="modal-body col-md-8 offset-md-2">
<div class="alert alert-danger print-error-msg" style="display:none">
<strong>Errors:</strong>
<ul></ul>
</div>
<div class="alert alert-success print-success-msg" style="display:none"></div>
{!! Form::open(['id'=>'contact-form']) !!}
<div class="form-group">
<input class="form-control" type="text" name="name" id="name" placeholder="Your Name">
</div>
<div class="form-group">
<input class="form-control" type="email" name="email" id="email" placeholder="Your Email">
</div>
<div class="form-group">
<textarea class="form-control" name="message" id="message" rows="3"></textarea>
</div>
<button type="button" class="btn btn-success btn-send-message"><i class="fas fa-paper-plane"></i>
Send Message <span id="loading" style="display: none;"><img class="loader"
src="{{ asset('images/loading.gif') }}"></span>
</button>
{!! Form::close() !!}
</div>
Use LaravelLocalization::getLocalizedURL() which returns an URL adapted to $locale.
So your ajax code will be.
$.ajax({
url: "{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(),'/contact') }}",
type:'POST',
data: $('#contact-form').serialize(),
beforeSend: function() {
$("#loading").show();
$(".fa-paper-plane").hide();
},
complete: function() {
$("#loading").hide();
$(".fa-paper-plane").show();
},
success: function(data) {
if($.isEmptyObject(data.error)){
printSuccessMsg();
}else{
printErrorMsg(data.error);
}
}
});
When you return your response try to use this helper __('translated_string')
To use this helper, you have to create some translate.php file in those folders resources/lang/en and resources/lang/en
For example:
File resources/lang/en/translate.php should contain this array
return [
'success_message' => 'Message sent successfully!',
];
File:
resources/lang/ru/translate.php should contain this array
return [
'success_message' => 'Сообщение успешно отправлено!',
];
For example:
return response()->json(['success'=> __('translate.success_message') ]);
To get some translated string, use dot notation for this helper;
Laravel localization helper

Multiple file upload using laravel and vue js error not print

Multiple file upload using vue js in laravel my validation is like
$request->validate([
'title' => 'required',
'pics.*' => 'required|image|mimes:jpeg,png,jpg,gif'
]);
and my component is like below
<template>
<div class="col-md-6">
<div class="form-group">
<label>Title</label>
<input id="title" type="text" ref="myDiv" v-model="title" class="form-control" name="title">
<div v-cloak><label class="error" v-if="errors['title']">{{ errors.title[0]
}}</label></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Upload Files</label>
<input id="uploadfile" type="file" ref="pics" name="pics[]" multiple class="form-control" #change="fieldChange">
<div v-cloak><label class="error" v-if="errors['pics']">{{ errors.pics[0] }}</label></div>
</div>
</div>
</template>
export default {
data(){
return {
attachments:[],
pics : [],
errors: [],
form: new FormData
}
},
methods:{
fieldChange(e){
let selectedFiles=e.target.files;
if(!selectedFiles.length){
return false;
}
for(let i=0;i<selectedFiles.length;i++){
this.attachments.push(selectedFiles[i]);
}
console.log(this.attachments);
},
uploadFile() {
this.errors = [];
this.form.append('img',this.attachments2);
if(this.attachments.length > 0){
for(let i=0; i<this.attachments.length;i++){
this.form.append('pics[]',this.attachments[i]);
}
}else {
this.form.append("pics", '');
}
//this.form.append('')
const config = { headers: { 'Content-Type':
'multipart/form-data' } };
axios.post('/admin/theme/',this.form,config).then(response=>
{
this.pics = [];
}).catch((error) => {
this.errors = error.response.data.errors;
console.log(this.errors.pics);
});
}
},
mounted() {
console.log('Component mounted.')
}
}
If i click to submit button empty title error print but multiple file error not print, i get error but not print
pics.0:["The pics.0 field is required."]
But title field validation error print perfectly
Please anyone help me to print multiple file upload error using vue js

Resources