Bootstrap Vue Input State - vue.js

Hi im trying to make a registration form. So when the user correctly inputs the correct detail it will display green check mark. When there is error in the input it will display an error below the input. However the input will still remain green as shown in the picture. How can I make it turn red?
Registeration form picture
Below is the code:
Code for the registeration form:
<b-form :validated="formValidation" novalidate>
<table align="center" style="width:100%">
<tr>
<td class="half">
<label>First Name:</label>
<b-form-input v-model="input.first_name.value" :state="input.first_name.state" placeholder="Enter First Name" required />
<b-form-invalid-feedback :state="input.first_name.state">{{ input.first_name.errMsg }}</b-form-invalid-feedback>
</td>
<td class="half">
<label>Last Name:</label>
<b-form-input v-model="input.last_name.value" :state="input.last_name.state" placeholder="Enter Last Name" required />
<b-form-invalid-feedback :state="input.last_name.state">{{ input.last_name.errMsg }}</b-form-invalid-feedback>
</td>
</tr>
<tr>
<td class="half">
<label>Email:</label>
<b-form-input v-model="input.email.value" :state="this.input.email.state" placeholder="Enter Email" required />
<b-form-invalid-feedback :state="input.email.state">{{ input.email.errMsg }}</b-form-invalid-feedback>
</td>
<td class="half">
<label>Phone Number:</label>
<b-form-input v-model="input.phone_no.value" :state="input.phone_no.state" placeholder="Enter Phone Number" required />
<b-form-invalid-feedback :state="input.phone_no.state">{{ input.phone_no.errMsg }}</b-form-invalid-feedback>
</td>
</tr>
<tr>
<td colspan="2" align="right">
<b-button variant="primary" align-h="end" #click="onSubmit">Submit</b-button><br/>
<br/>
</td>
</tr>
</table>
</b-form>
Code for the script part:
import { register } from "#/api/auth.js"
export default {
name: "RegisterUser",
data() {
return {
formValidation: null,
input: {
first_name: {
value: '',
errMsg: null,
state: null
},
last_name: {
value: '',
errMsg: null,
state: null
},
email: {
value: '',
errMsg: null,
state: null
},
phone_no: {
value: '',
errMsg: null,
state: null
}
}
},
created() {
if(this.$session.flash.get("flash-message")) {
this.$bvToast.toast(this.$session.flash.get("flash-message"), { autoHideDelay: 5000, variant: this.$session.flash.get("flash-class"), solid: true })
}
},
methods: {
onSubmit() {
// Form Validation
this.formValidation = true
var doSubmit = true
this.input.password.errMsg = null
this.input.confirm_password.errMsg = null
if (this.input.first_name.value == "" || this.input.first_name.value == null) {
doSubmit = false
this.input.first_name.errMsg = "First Name must not be empty"
}
if (this.input.last_name.value == "" || this.input.last_name.value == null) {
doSubmit = false
this.input.last_name.errMsg = "Last Name must not be empty"
}
if (this.input.email.value == "" || this.input.email.value == null) {
doSubmit = false
this.input.email.errMsg = "Email must not be empty"
}
if (this.input.phone_no.value == "" || this.input.phone_no.value == null) {
doSubmit = false
this.input.phone_no.errMsg = "Phone Number must not be empty"
}
let userObj= {
first_name : this.input.first_name.value,
last_name : this.input.last_name.value,
email : this.input.email.value,
phone_no : this.input.phone_no.value,
};
// Submit
if (doSubmit) {
try {
register(userObj)
.then(async (response) => {
if (await response.data.status) {
await this.$bvToast.toast(response.data.message, { autoHideDelay: 5000, variant: "success", solid: true })
await this.$session.flash.set("flash-class", "success")
await this.$session.flash.set("flash-message", "Registration successful")
await this.$session.set("email", userObj.email)
await new Promise(r => setTimeout(r, 2000));
// await this.$router.push({ name: "password.success" })
await this.$router.push({ name: "register.success" })
this.formValidation = false
} else {
await this.$bvToast.toast(response.data.message, { autoHideDelay: 5000, variant: "danger", solid: true })
}
})
.catch((e) => {
// this.$bvToast.toast(res.data.message, { autoHideDelay: 5000, variant: "danger", solid: true })
// console.log("Testing: " + e.response.status)
if(e.response.status && e.response.status == 422) {
// this.$toast.add({severity:'error', summary: 'Error', detail: e.response.data.message, life: 5000})
this.$bvToast.toast(e.response.data.message, { autoHideDelay: 5000, variant: "danger", solid: true })
if(e.response.data.errors) {
let errObj = e.response.data.errors
this.input.email.errMsg = errObj.email ? errObj.email[0] : null
this.input.email.state = false
console.log("Email State: " + this.input.email.state)
this.input.phone_no.errMsg = errObj.phone_no ? errObj.phone_no[0] : null
this.input.phone_no.state = false
return {
input: {
email: {
state: false
},
phone_no: {
state: false
},
}
}
}
} else {
this.$bvToast.toast("Registration failed. Please try again later.", { autoHideDelay: 5000, variant: "danger", solid: true })
}
})
.finally(() => {
this.loadingIndicator = false
})
} catch(e) {
console.error(e)
}
}
}
}
}
Anyone knows what i'm doing wrong?

Related

How to set the content of first row as headers?

How to set the content of first row as headers ?
<template>
<v-container>
<div #drop="_drop" #dragenter="_suppress" #dragover="_suppress">
<input
type="file"
class="form-control"
id="file"
:accept="SheetJSFT"
#change="_change"
/>
<v-btn :disabled="data.length ? false : true" #click="_export">
Export
</v-btn>
<table class="table table-striped">
<thead>
<tr>
<th v-for="c in cols" :key="c.key">{{ c.name }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(r, key) in data" :key="key">
<td v-for="c in cols" :key="c.key">{{ r[c.key] }}</td>
</tr>
</tbody>
</table>
</div>
</v-container>
</template>
<script>
import XLSX from 'xlsx'
const make_cols = (refstr) =>
Array(XLSX.utils.decode_range(refstr).e.c + 1)
.fill(0)
.map((x, i) => ({ name: XLSX.utils.encode_col(i), key: i }))
const _SheetJSFT = [
'xlsx',
'xlsb',
'xlsm',
'xls',
'xml',
'csv',
'txt',
'ods',
'fods',
'uos',
'sylk',
'dif',
'dbf',
'prn',
'qpw',
'123',
'wb*',
'wq*',
'html',
'htm',
]
.map(function (x) {
return '.' + x
})
.join(',')
export default {
data() {
return {
data: ['SheetJS'.split(''), '1234567'.split('')],
cols: [
{ name: 'A', key: 0 },
{ name: 'B', key: 1 },
{ name: 'C', key: 2 },
{ name: 'D', key: 3 },
{ name: 'E', key: 4 },
{ name: 'F', key: 5 },
{ name: 'G', key: 6 },
],
SheetJSFT: '.xlsx',
}
},
methods: {
_suppress(evt) {
evt.stopPropagation()
evt.preventDefault()
},
_drop(evt) {
evt.stopPropagation()
evt.preventDefault()
const files = evt.dataTransfer.files
if (files && files[0]) this._file(files[0])
},
_change(evt) {
const files = evt.target.files
if (files && files[0]) this._file(files[0])
},
_export(evt) {
/* convert state to workbook */
const ws = XLSX.utils.aoa_to_sheet(this.data)
const wb = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS')
/* generate file and send to client */
XLSX.writeFile(wb, 'sheetjs.xlsx')
},
_file(file) {
/* Boilerplate to set up FileReader */
const reader = new FileReader()
reader.onload = (e) => {
/* Parse data */
const ab = e.target.result
const wb = XLSX.read(new Uint8Array(ab), { type: 'array' })
/* Get first worksheet */
const wsname = wb.SheetNames[0]
const ws = wb.Sheets[wsname]
/* Convert array of arrays */
const data = XLSX.utils.sheet_to_json(ws, { header: 1, range: 1 })
/* Update state */
const data = XLSX.utils.sheet_to_json(ws, { header: 1 })
/* Update state */
this.data = data
this.cols = make_cols(ws['!ref'])
}
reader.readAsArrayBuffer(file)
},
},
}
</script>

Vuejs: vuelidate conditional validation

suppose we have a password field and we want to do some validations of length, specialcharacters, numbers, upper case and lower case etc, only if the field has a value
how can we do that with vuelidate.
here I am import vuelidate
import { required, minLength, maxLength, email, sameAs } from 'vuelidate/lib/validators'
Here the validations
validations: {
editedItem: {
firstname: { required, minLength: minLength(3), maxLength: maxLength(20) },
lastname: { required, minLength: minLength(3), maxLength: maxLength(20) },
email: { required, email },
password: {
required,
minLength: minLength(6),
maxLength: maxLength(15),
oneNumber,
oneUpperCase,
oneLowerCase,
},
repassword: {
sameAsPassword: sameAs('password'),
},
},
}
,
oneNumber, oneUpperCase and oneLowerCase are custom validations:
const oneNumber = (value) => /[0-9]/.test(value)
const oneUpperCase = (value) => /[A-Z]/.test(value)
const oneLowerCase = (value) => /[a-z]/.test(value)
I will forever appreciate any help or advice
My solution involves a separate "custom validators" file.
validators.js:
import { helpers as vuelidateHelpers } from 'vuelidate/lib/validators'
export const oneUppercase = value => {
if (!vuelidateHelpers.req(value)) {
return true
}
const match = value.match(/[A-Z]/g) || []
return match.length >= 1
}
export const oneLowercase = value => {
if (!vuelidateHelpers.req(value)) {
return true
}
const match = value.match(/[a-z]/g) || []
return match.length >= 1
}
export const oneSpecial = value => {
if (!vuelidateHelpers.req(value)) {
return true
}
const match = value.match(/[ !##$%^&*()_+\-=[\]{};':"\\|,.<>/?]/g) || []
return match.length >= 1
}
export const oneNumber = value => {
if (!vuelidateHelpers.req(value)) {
return true
}
const match = value.match(/\d/g) || []
return match.length >= 1
}
In the component, with visual formatting to let the user know if their password meets the requirement:
<template>
<form>
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
v-model="form.password"
#blur="$v.form.password.$touch()"
#input="validatePassword"
/>
<label for="confirmPassword">Confirm Password</label>
<input
id="confirmPassword"
name="confirmPassword"
type="password"
v-model="form.confirmPassword"
#blur="$v.form.confirmPassword.$touch()"
/>
<ul>
<li>
{{
passwordValidations.eightCharacters ?
'✓':
'╳'
}}
<span class="ml-1">MUST contain 8 characters</span>
</li>
<li>
{{
passwordValidations.oneUppercase ?
'✓':
'╳'
}}
<span class="ml-1">MUST contain one uppercase letter</span>
</li>
<li>
{{
passwordValidations.oneLowercase ?
'✓':
'╳'
}}
<span class="ml-1">MUST contain one lowercase letter</span>
</li>
<li>
{{
passwordValidations.oneNumber ?
'✓':
'╳'
}}
<span class="ml-1">MUST contain one number</span>
</li>
<li>
{{
passwordValidations.oneSpecial ?
'✓':
'╳'
}}
<span class="ml-1">MUST contain one special character</span>
</li>
</ul>
</form>
</template>
<script>
import {
required,
minLength,
sameAs,
} from 'vuelidate/lib/validators'
import {
oneNumber,
oneSpecial,
oneUppercase,
oneLowercase,
} from '../validators'
export default {
data () {
return {
form: {
password: '',
confirmPassword: '',
},
passwordValidations: {
eightCharacters: false,
oneUppercase: false,
oneLowercase: false,
oneNumber: false,
oneSpecial: false,
},
}
},
computed: {
passwordErrors () {
const errors = []
if (!this.$v.form.password.$dirty) return errors
!this.$v.form.password.required && errors.push('Password is required.')
return errors
},
confirmPasswordErrors () {
const errors = []
if (!this.$v.form.confirmPassword.$dirty) return errors
!this.$v.form.confirmPassword.required && errors.push('Please confirm your password.')
!this.$v.form.confirmPassword.sameAsPassword && errors.push('Passwords don\'t match')
return errors
},
},
methods: {
validatePassword () {
this.passwordValidations.eightCharacters = this.$v.form.password.eightCharacters
this.passwordValidations.oneUppercase = this.$v.form.password.oneUppercase
this.passwordValidations.oneLowercase = this.$v.form.password.oneLowercase
this.passwordValidations.oneNumber = this.$v.form.password.oneNumber
this.passwordValidations.oneSpecial = this.$v.form.password.oneSpecial
},
},
validations: {
form: {
password: {
required,
minLength: minLength(8),
oneUppercase,
oneSpecial,
oneNumber,
oneLowercase,
},
confirmPassword: {
required,
sameAsPassword: sameAs('password'),
},
},
},
}
</script>

Vuelidate minvalue optionnal

I would like to validate a value 'stock' which is optionnal. I'm using vuelidate (https://monterail.github.io/vuelidate/)
Value 'stock' must be greater than 0 if an other value ('price') is greater than 0
If 'price' value is not defined, the validator of stock value must be disabled
price is an input value (decimal number), stock is a slider (number)
[EDIT]
Example of code
<template>
<form #submit.prevent="submit" class="offer-form">
<q-field label="Prix initial" helper="Indiquer le prix initial de l'offre" :error="hasItemError('price')" :error-label="itemErrorLabel('price')">
<q-input type="number" color="input" #blur="$v.item.price.$touch()" v-model="item.price" />
</q-field>
<q-field label="Stock" helper="Indiquer le nombre de stock" :error="hasItemError('stock')" :error-label="itemErrorLabel('stock')">
<q-slider color="input" label-always label :step=1 :min="0" #blur="$v.item.stock.$touch()" :max="50" v-model="item.stock"/>
</q-field>
<q-btn
icon="fas fa-check"
label="Valider"
color="green"
#click="submit"
/>
</form>
</template>
<script>
import { required, requiredIf, decimal, minValue } from 'vuelidate/lib/validators'
export default {
data () {
return {
item: {
id: null,
title: '',
description: '',
price: null,
reductionPercentage: 15,
stock: 0,
startDate: new Date(),
endDate: null,
product: null,
shop: null,
images: []
},
},
validations: {
item: {
title: { required },
startDate: { required },
endDate: { required },
price: { decimal },
reductionPercentage: {
requiredIf: requiredIf((vueInstance) => {
return vueInstance.price > 0
}),
minValue: minValue(15)
},
stock: {
requiredIf: requiredIf((vueInstance) => {
return vueInstance.price > 0
}),
// minValue ???
}
}
},
methods: {
submit () {
this.onSubmit = true
if (this.isValidate()) {
// Validation ok
}
this.onSubmit = false
},
isValidate () {
this.$v.item.$touch()
if (this.$v.item.$error) {
this.$q.notify({message: 'Vérifiez les champs en erreur', position: 'center'})
return false
}
return true
}
}
}
I tested this but it's not ok =>
minValue: minValue((vueInstance) => {
return vueInstance.price > 0 ? vueInstance.stock > 0 : true
})
How can I do this ?
Thanks
You dont offer a lot of code so it is hard to understand your goal,but i will try,just tell me if it is what you wanted :)
Validator of Stock is a Checkbox or a function or ?
var app = new Vue({
el: '#app',
data: {
price: 0,
stock: 0,
},
computed: {
stockvalidator: function()
{
if(this.price > 0 && this.stock > 0) return true
else if(this.price > 0 && this.stock <= 0) return false
else return false
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<input type="number" v-model="price">
Price: {{price}}
<input type="number" v-model="stock">
Stock: {{stock}}
<br>
<input :disabled="!stockvalidator" type="checkbox"> Stock Validator is {{stockvalidator}}
</div>
Not sure if you are strugling with this still, or there is anyone out there with the same issue, but here is my two cents:
minValue: (stockValue, item) => {
return item.price > 0 ? stockValue > 0 : true
})
Cheers!
I think you can do this:
stock: {
requiredIf: requiredIf(() => {
return this.price > 0 || this.price
}),
minvalue: helpers.withMessage(
"The minimum value for the stock is 0",
helpers.withAsync(async value => {
let retvalue;
if(this.price > 0 && value > 0){
retvalue = true;
}
else if (this.price > 0 && value <= 0){
retvalue = false;
}
else{
retvalue = true;
}
return retvalue;
})
)
}
Remember import "helpers" from vuelidate.
And I advise you to make your own file with your custom validators, then you can use it in every places in your project. Something like utils/customValidators.js.

How to apply individual error message in VueJs Element?

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.
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;
},
},
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);
}
}
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,
Bind individual input error with errors.get('field') e.g :error="errors.get('email')"
Import Error class (see snippet below)
Add errors object to vue data
Make axios request and record response data
<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 = {};
}
}
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>

Remove category_id property from ColumnValue object in Vue template

I want to remove category_id from {{ columnValue }}, but what is the best way to to that, because i need category_id in the first part ?
<table>
<tr>
<td v-for="columnValue, column in record">
<template v-if="editing.id === record.id && isUpdatable(column)">
<template v-if="columnValue === record.category_id">
<select class="form-control" v-model="editing.form[column]">
<option v-for="column in response.joins">
{{ column.category }} {{ column.id }}
</option>
</select>
</template>
<template v-else="">
<div class="form-group">
<input class="form-control" type="text" v-model= "editing.form[column]">
<span class="helper-block" v-if="editing.errors[column]">
<strong>{{ editing.errors[column][0]}}</strong>
</span>
</div>
</template>
</template>
<template v-else="">
{{ columnValue }} // REMOVE category_id here!
</template>
</td>
</tr>
</table>
And the view (its the number under group i want to remove):
The DataTable view
The script:
<script>
import queryString from 'query-string'
export default {
props: ['endpoint'],
data () {
return {
response: {
table: null,
columntype: [],
records: [],
joins: [],
displayable: [],
updatable: [],
allow: {},
},
sort: {
key: 'id',
order: 'asc'
},
limit: 50,
quickSearchQuery : '',
editing: {
id: null,
form: {},
errors: []
},
search: {
value: '',
operator: 'equals',
column: 'id'
},
creating: {
active: false,
form: {},
errors: []
},
selected: []
}
},
filters: {
removeCategoryId: function (value) {
if (!value) return ''
delete value.category_id
return value
}
},
computed: {
filteredRecords () {
let data = this.response.records
data = data.filter((row) => {
return Object.keys(row).some((key) => {
return String(row[key]).toLowerCase().indexOf(this.quickSearchQuery.toLowerCase()) > -1
})
})
if (this.sort.key) {
data = _.orderBy(data, (i) => {
let value = i[this.sort.key]
if (!isNaN(parseFloat(value)) && isFinite(value)) {
return parseFloat(value)
}
return String(i[this.sort.key]).toLowerCase()
}, this.sort.order)
}
return data
},
canSelectItems () {
return this.filteredRecords.length <=500
}
},
methods: {
getRecords () {
return axios.get(`${this.endpoint}?${this.getQueryParameters()}`).then((response) => {
this.response = response.data.data
})
},
getQueryParameters () {
return queryString.stringify({
limit: this.limit,
...this.search
})
},
sortBy (column){
this.sort.key = column
this.sort.order = this.sort.order == 'asc' ? 'desc' : 'asc'
},
edit (record) {
this.editing.errors = []
this.editing.id = record.id
this.editing.form = _.pick(record, this.response.updatable)
},
isUpdatable (column) {
return this.response.updatable.includes(column)
},
toggleSelectAll () {
if (this.selected.length > 0) {
this.selected = []
return
}
this.selected = _.map(this.filteredRecords, 'id')
},
update () {
axios.patch(`${this.endpoint}/${this.editing.id}`, this.editing.form).then(() => {
this.getRecords().then(() => {
this.editing.id = null
this.editing.form = {}
})
}).catch((error) => {
if (error.response.status === 422) {
this.editing.errors = error.response.data.errors
}
})
},
store () {
axios.post(`${this.endpoint}`, this.creating.form).then(() => {
this.getRecords().then(() => {
this.creating.active = false
this.creating.form = {}
this.creating.errors = []
})
}).catch((error) => {
if (error.response.status === 422) {
this.creating.errors = error.response.data.errors
}
})
},
destroy (record) {
if (!window.confirm(`Are you sure you want to delete this?`)) {
return
}
axios.delete(`${this.endpoint}/${record}`).then(() => {
this.selected = []
this.getRecords()
})
}
},
mounted () {
this.getRecords()
},
}
</script>
And here is the json:
records: [
{
id: 5,
name: "Svineskank",
price: "67.86",
category_id: 1,
category: "Flæskekød",
visible: 1,
created_at: "2017-09-25 23:17:23"
},
{
id: 56,
name: "Brisler vv",
price: "180.91",
category_id: 3,
category: "Kalvekød",
visible: 0,
created_at: "2017-09-25 23:17:23"
},
{
id: 185,
name: "Mexico griller 500 gram",
price: "35.64",
category_id: 8,
category: "Pølser",
visible: 0,
created_at: "2017-09-25 23:17:23"
},
{
id: 188,
name: "Leverpostej 250 gr.",
price: "14.25",
category_id: 9,
category: "Pålæg",
visible: 1,
created_at: "2017-09-25 23:17:23"
},
}]
.. and so on......
I would recommend using a filter in Vue to remove the property, such as:
new Vue({
// ...
filters: {
removeCategoryId: function (value) {
if (!value) return ''
delete value.category_id
return value
}
}
})
An then use this in your template:
{{ columnValue | removeCategoryId }}
Update: I misunderstood the scope of the loop. This works, and I verified on jsfiddle: https://jsfiddle.net/spLxew15/1/
<td v-for="columnValue, column in record" v-if="column != 'category_id'">