Reputation: 193
I have a form (http://element.eleme.io/#/en-US/component/form) in application, where I do server side validation. But I have not glu how to add error message for specific inputs.
Upvotes: 0
Views: 7873
Reputation: 343
add a ref with any name and do the following:
In js do this
this.$refs.formData.errorBucket=[]
<v-text-field
ref="formData"
:rules="[rules.required, rules.max]">
</v-text-field>
Upvotes: 0
Reputation: 11
I figured out a Laravel solution based on Laracast project. The advantage of this approach is that the Error class is reusable.
In your component.vue,
<template>
<el-form label-position="top"
label-width="100px"
:model="loginForm"
:rules="rules"
@submit.prevent="validateForm"
ref="loginForm"
status-icon validate-on-rule-change>
<el-form-item label="email" prop="email" :error="errors.get('email')">
<el-input v-model="loginForm.email" placeholder="Enter your email"></el-input>
</el-form-item>
<el-form-item label="password" prop="password" :error="errors.get('password')">
<el-input v-model="loginForm.password" placeholder="Enter your password"></el-input>
</el-form-item>
<!-- Note about get() method in :error="errors.get('password')" see errors js -->
</el-form>
</template>
<script>
import { Errors } from './../templates/errors.js';
export default {
// Data
data() {
return {
loginForm: {
email: '',
password: '',
},
// This is where we manage laravel errors
errors: new Errors(),
// Local validation disabled
rules: {
email: [
{ required: false, message: 'Please enter your email', trigger: 'blur' },
// required set to false to for the sake of testing with laravel
],
password: [
{ required: false, message: 'Please enter your password', trigger: 'blur' },
// required set to false to for the sake of testing with laravel
],
}
};
},
// Methods
methods: {
// Validate form data
submitForm(loginForm) {
// Clear Laravel errors before submitting form
this.errors.clear()
this.$refs[loginForm].validate((valid) => {
if (valid && ! this.errors.any()) {
console.log('Data is validated. Submitting' + this.loginForm);
this.login()
this.$refs[loginForm].validate()
} else {
console.log('Cannot submit, Invalid data');
return false;
}
});
},
// post data
login(){
axios.post('/login'.login, this.loginForm).then( response => {
// Data submitted successifully
})
.catch(error => {
// There was an error like
this.errors.record(error.response.data.errors)
// Note: see errors.js for record method
});
}
}
}
</script>
Then import errors.js (credit Laracast project)
export class Errors {
/**
* Create a new Errors instance.
*/
constructor() {
this.errors = {};
}
/**
* Determine if an errors exists for the given field.
*
* @param {string} field
*/
has(field) {
return this.errors.hasOwnProperty(field);
}
/**
* Determine if we have any errors.
*/
any() {
return Object.keys(this.errors).length > 0;
}
/**
* Retrieve the error message for a field.
*
* @param {string} field
*/
get(field) {
if (this.errors[field]) {
return this.errors[field][0];
}
}
/**
* Retrieve flash message if any
*
* @param {string} field
*/
getFlash(field) {
if (this.errors[field]) {
return this.errors[field];
}
}
/**
* Record the new errors.
*
* @param {object} errors
*/
record(errors) {
this.errors = errors;
}
/**
* Clear one or all error fields.
*
* @param {string|null} field
*/
clear(field) {
if (field) {
if (this.has(field)) {
delete this.errors[field];
}
return;
}
this.errors = {};
}
}
Upvotes: 0
Reputation: 3397
Each el-form-item
needs a prop attribute for the frontend validation to work. They also need a bound error attribute. I just made each the same as the field name for simplicity, like so:
<el-form-item label="Email" prop="email" :error="errors.email">
<el-input v-model="form.email" type="email"></el-input>
</el-form-item>
Then when the form is submitted I run my validator for the frontend rules (using Element's rules). Right after that I use axios to post to the server (Laravel). I loop through any errors, and update the value in the errors object. Whenever the form is submitted, I clear the errors (if you don't clear them, the errors will not show up on consecutive form submissions).
data() {
let passwordsMatch = (rule, value, callback) => {
if ( value != this.form.password )
return callback(new Error('Passwords do not match'));
return callback();
};
let form = {
first_name: '',
last_name: '',
email: '',
phone: '',
password: '',
password_confirmation: '',
};
// copy blank values, not reference
let errors = {...form};
let blankErrors = {...form};
return {
form,
errors,
blankErrors,
rules: {
first_name: [
{ required: true, message: 'First Name is required', trigger: 'blur' },
],
last_name: [
{ required: true, message: 'Last Name is required', trigger: 'blur' },
],
email: [
{ required: true, message: 'Email is required', trigger: 'blur' },
{ type: 'email', message: 'Must be an email', trigger: 'blur' },
],
phone: [
{ required: true, message: 'Cell Phone is required', trigger: 'blur' },
// TODO: finish phone validation
//{ type: 'number', message: 'Must be a phone number', trigger: 'blur' },
],
password: [
{ required: true, message: 'Password is required', trigger: 'blur' },
],
password_confirmation: [
{ required: true, message: 'Password is required', trigger: 'blur' },
{ validator: passwordsMatch, trigger: 'blur' },
],
},
}
},
methods: {
createAccount() {
this.clearErrors();
let passed = this.runValidator();
if (! passed) return;
axios.post(`/register`, this.form)
.then(response => {
EventBus.$emit('user-form-completed', this.form);
return;
})
.catch(error => {
const errors = error.response.data.errors;
for (let index in errors) {
let error = errors[index][0];
this.errors[index] = error;
}
});
},
clearErrors() {
this.errors = {...this.blankErrors};
},
runValidator() {
let passed = false;
this.$refs.form.validate((valid) => {
if (valid) passed = true;
});
return passed;
},
},
Upvotes: 1
Reputation: 34914
I am using Laravel and I usually do like this, My validation in Laravel controller
return Validator::make($data, [
'email' => 'required|email',
'password' => 'required|min:6',
]);
My vue.js code in if error comes
if(error.response.status == 400){
let errors = error.response.data.errors;
for(let i in errors){
document.querySelector("div[for='"+i+"']").innerHTML = errors[i][0];
}
}else if(error.response.status == 401){
console.log(error.response);
let errors = error.response.data;
document.querySelector("div[for='password']").innerHTML = errors;
}
Complete vue component is
const Login = {
template: `
<div class="container">
<div class="row row-body">
<div class="col-12 col-md-6 offset-md-3">
<div class="row">
<div class="col-12 col-md-12 text-center">
<h1>Login</h1>
</div>
</div>
<div class="row">
<div class="col-12 col-md-12">
<form method="POST" action="">
<div class="row pt-3 pb-3">
<div class="col-12 col-md-10 offset-md-1 form-group">
<input class="form-control form-rounded" placeholder="Email*" v-model="email">
<div for="email" class="text-danger"></div>
</div>
</div>
<div class="row pb-3">
<div class="col-12 col-md-10 offset-md-1 form-group">
<input class="form-control" placeholder="Password*" v-model="password" type="password">
<div for="password" class="text-danger"></div>
</div>
</div>
<div class="row pt-3">
<div class="col-12 col-md-12 form-group text-center">
<button @click="login" class="btn as-btn-outline as-btn-dark mx-2 my-2 my-sm-0 big-btn" type="button">LOGIN</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
`,
data(){
return {
email: '',
password: ''
}
},
mounted(){
/**/
},
methods:{
login: function(){
var formdata = {};
formdata.email = this.email;
formdata.password = this.password;
axios
.post('http://far.test/api/login',formdata)
.then(response => {
console.log(response.data);
if(response.data.token !== undefined){
this.$parent.is_auth = true;
sessionStorage.setItem('asset_token', response.data.token);
router.push({ path: '/home' });
}
})
.catch(error => {
if(error.response.status == 400){
let errors = error.response.data.errors;
for(let i in errors){
document.querySelector("div[for='"+i+"']").innerHTML = errors[i][0];
}
}else if(error.response.status == 401){
console.log(error.response);
let errors = error.response.data;
document.querySelector("div[for='password']").innerHTML = errors;
}
})
.finally(() => console.log('finally')/*this.loading = false*/);
},
}
}
And related laravel controller methods are
public function validateAuditLogin($data){
return Validator::make($data, [
'email' => 'required|email',
'password' => 'required|min:6',
]);
}
public function loginForAudit(Request $request){
$requestAll = $request->all();
$pwd = base64_decode($requestAll["password"]);
for($i=0;$i<4;$i++){
$pwd = base64_decode($pwd);
}
$requestAll['password'] = $pwd;
$validator = $this->validateAuditLogin($requestAll);
if($validator->fails()){
return response()->json(['errors'=>$validator->messages()],400);
}
if ($user = \Auth::attempt(['email' => $requestAll['email'], 'password' => $requestAll['password'] ])) {
$token = str_random(40);
User::where('id',\Auth::id())->update(['api_token'=>$token]);
return response()->json(['token'=>$token]);
}else{
return response()->json('Email or password is incorrect',401);
}
}
Upvotes: 0