Uncaught (in promise) csrf Vue js laravel - 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

Related

How to fix Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'status') at app.js

I had the following code and everything was working as expected.
<template>
<div id="login">
<form #submit.prevent="submit">
<p class="loading" :class="{ hideLoad: !loading }">Loading...</p>
<label for="email">Email</label>
<input type="text" id="email" v-model="fields.email" />
<span v-if="errors && errors.email" class="error">{{
errors.email[0]
}}</span>
<label for="password">Password</label>
<input type="password" id="password" v-model="fields.password" />
<span v-if="errors && errors.password" class="error">{{
errors.password[0]
}}</span>
<button type="submit">Log In</button>
<span
>Don't have an account?
<router-link :to="{ name: 'Register' }">Sign Up</router-link></span
>
</form>
</div>
</template>
<script>
export default {
data() {
return {
fields: {},
errors: {},
loading: false,
};
},
methods: {
submit() {
this.loading = true;
axios
.post("/api/login", this.fields)
.then((res) => {
if (res.status == 201) {
localStorage.setItem("authenticated", "true");
this.$router.push({ name: "Dashboard" });
}
})
.catch((error) => {
if (error.response.status == 422) {
this.errors = error.response.data.errors;
this.loading = false;
}
});
},
},
};
</script>
I then decided to use pinia to manage state and came up with the following.
<template>
<div id="login">
<form #submit.prevent="loginStore.submit">
<p class="loading" :class="{ hideLoad: !loginStore.loading }">Loading...</p>
<label for="email">Email</label>
<input type="text" id="email" v-model="loginStore.fields.email" />
<span v-if="loginStore.errors && loginStore.errors.email" class="error">{{
loginStore.errors.email[0]
}}</span>
<label for="password">Password</label>
<input type="password" id="password" v-model="loginStore.fields.password" />
<span v-if="loginStore.errors && loginStore.errors.password" class="error">{{
loginStore.errors.password[0]
}}</span>
<button type="submit">Log In 2</button>
<span
>Don't have an account?
<router-link :to="{ name: 'Register' }">Sign Up</router-link></span
>
</form>
</div>
</template>
<script setup>
import {useLoginStore} from '../stores/login'
const loginStore = useLoginStore();
</script>
My login.js
import { defineStore } from 'pinia'
export const useLoginStore = defineStore('login', {
state: () => {
return {
fields: {},
errors: {},
loading: false,
}
},
actions: {
submit() {
this.loading = true;
axios
.post("/api/login", this.fields)
.then((res) => {
if (res.status == 201) {
localStorage.setItem("authenticated", "true");
this.$router.push({ name: "Dashboard" });
}
})
.catch((error) => {
if (error.response.status == 422) {
this.errors = error.response.data.errors;
this.loading = false;
}
});
},
},
})
Everything is working as before and the only error is that when I fill the form with the correct credential and submit then I get Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'status') at app.js
I've tried all I can and I just can't figure out what it is that I'm doing wrong.
After debugging it further, I realized the error was coming from this.$routerinstance since a user gets login successfully and the status code is okay when I console log.
The instance is available in components only https://router.vuejs.org/api/#component-injected-properties
So, I fixed the problem by importing router in the store.js file,
import router from '../router'
then I pushed to another route by just using
router.push({ name: "Dashboard" });
instead of this.$router.push({ name: "Dashboard" });

How to store logged In user_id in vuejs

I am totally new in vew js and I am trying to store data in db and I am storing successfully when I entered the values manually but I want to store the user_id of logged in user.
Here is my vue
<form #submit.prevent>
<div class="form-group">
<label for="event_name">Name</label>
<input type="text" id="event_name" class="form-control" v-model="newEvent.event_name">
</div>
<div class="form-group">
<label for="user_id">Use Id</label>
<input type="text" id="user_id" class="form-control" v-model="newEvent.user_id">
</div>
<div class="col-md-6 mb-4" v-if="addingMode">
<button class="btn btn-sm btn-primary" #click="addNewEvent">Save Event</button>
</div>
</form>
export default {
components: {
Fullcalendar
},
data() {
return {
calendarPlugins: [dayGridPlugin, interactionPlugin],
events: "",
newEvent: {
event_name: "",
user_id: ""
},
addingMode: true,
indexToUpdate: ""
};
},
created() {
this.getEvents();
},
methods: {
addNewEvent() {
axios
.post("/fullcalendar/api/calendar", {
...this.newEvent
})
.then(data => {
this.getEvents(); // update our list of events
this.resetForm(); // clear newEvent properties (e.g. title and user_id)
})
.catch(err =>
console.log("Unable to add new event!", err.response.data)
);
},
Here, when I enter values in Name and User Id manually then it stores in db but in user id I want to get the logged in user_id.
I have tried something like this but it didn't work,
<input type="text" id="user_id" class="form-control" v-model="newEvent.{{ Auth::user()->id; }}">
Please help me out, Thanks in advance.
EventResource.php
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->event_name,
'user' => $this->user_id,
];
}
you can send data with your axios request like this:
axios.post('/url', {
user_id: {{ Auth::user()->id }}
}, {
headers: headers
})
and in your controller you can access it with:$request->user_id;

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

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.

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

Using axios in Vue but data is not loading asynchronously

I'm using Laravel with Vue as a front-end framework, and for ajax calls I'm using axios, but data is loading only when the page is refreshed.
Routes:
Route::get('/comment','CommentController#show');
Route::post('/store','CommentController#store');
Vue component:
<template>
<div>
<form>
<div class="form-group">
<label>title</label>
<input v-model="comment.title" type="text" class="form-control">
</div>
<div class="form-group">
<label>body</label>
<textarea v-model="comment.body" class="form-control" placeholder="Add comment.."></textarea>
</div>
<button #click.prevent="add()" class="btn btn-primary">Comment</button>
</form>
</div>
</template>
<script>
export default {
data(){
return{
comment:{
title:"",
body:""
}
}
},
methods:{
add: function(){
axios.post('/store',{
title: this.comment.title,
body: this.comment.body
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
}
</script>
CommentController:
public function show(){
$comments= comment::orderby('id','desc')->get();
return $comments;
}
public function store(Request $request){
$this->validate($request,[
'title'=> 'required',
'body' => 'required'
]);
comment::create([
'title'=> request('title'),
'body' => request('body')
]);
return redirect('/');
}

Resources