Vee-validate and vuetify checkbox group with v-for - vue.js

I have some problem with vee-validate, vuetify and v-for.
There is my code :
<ValidationProvider
name="availableLanguages"
rules="required"
v-slot="{ errors }"
>
<v-row>
<v-col
cols="2"
v-for="availableLanguage in availableLanguages"
:key="availableLanguage.label"
>
<v-checkbox
v-model="selectedLanguage"
:label="availableLanguage.label"
:value="availableLanguage.value"
:error="errors.length > 0"
hide-details
#click="setDefaultLanguage"
key="availableLanguage-input"
/>
</v-col>
</v-row>
<v-row>
<v-col
cols="12"
class="errorCheckBox"
>
{{ errors[0] }}
</v-col>
</v-row>
</ValidationProvider>
What is the expected result ?
I have a checkbox group. I want if all checkboxes are unchecked then an error message appear.
What's happened ?
If i don't click once on the first iteration of the v-for loop, the error is not trigger.
Thanks for help.

By default, the Validationprovider doesn't validate as soon as form is rendered, but only does it when the field has been touched. You can use immediate prop to make the field be validated when rendered:
<ValidationProvider
name="availableLanguages"
rules="required"
immediate
v-slot="{ errors }"
>

Related

computed property is not updating value in v-text-field after execution

I am doing this excercise in vue.js 2.6.
I have a toggled button that has two values: '1' or '2', and I made a computed that depending on these previous values return other values.
this returns either '1' or '2'
<v-col cols="12" sm="12" md="4" lg="4" xl="4">
<label>Toggle button</label><br />
<v-btn-toggle v-model="backendprop.prop1" color="blue" class="form-control p-0" dense borderless>
<v-btn v-for="option in BackendProp1" :key="option.value" :value="option.value">{{ option.label }}</v-btn>
</v-btn-toggle>
</v-col>
I want the value of this input to update according to computed setValueBecauseToggledButton
<v-col cols="12" sm="12" md="4" lg="4" xl="4">
<label>Value depending on Toggled Button</label><br />
<v-text-field
v-model="backendprop.prop2"
type="text"
disabled
outlined
dense
:value="setValueBecauseToggledButton"
/>
</v-col>
and this is the computed value:
computed:{
setValueBecauseToggledButton(){
return this.backendprop?.prop1?.toString() === '2' ? 'Valid prop' : ''
}
The behavior I expect is when I choose between the options of one input the other input should be updated.
Placing console.log in setValueBecauseToggledButton shows me that is working perfectly, but it does nothing on the v-text-field.
You could set a watcher on your property and then update the value for the v-text-field inside it.
<v-col cols="12" sm="12" md="4" lg="4" xl="4">
<label>Value depending on Toggled Button</label><br />
<v-text-field
v-model="backendprop.prop2"
type="text"
disabled
outlined
dense
/>
</v-col>
watch: {
'backendprop.prop1'(value){
this.backendprop.prop2 = value.toString() === '2' ? 'Valid prop' : ''
}
}

Is there a way to toggle visibility for multiple password fields with a dynamic form using vuetify vuejs?

I have a dynamic form that is constructed based off of json from the backend of input types, id, names, values, etc. One of my forms has two password fields that come from the backend. Is there a way to toggle visibility for multiple password fields on the same dynamic form? I'm having trouble figuring out how to do this to one at a time. Right now, the toggle icon switches both password fields on the screen.
<template>
<div class="pb-4" >
<template v-for="formField in formFields">
<v-row
:key="formField.key"
dense
align="center"
>
<v-col
md="3"
class="font-weight-bold text-right pr-10"
align-self="center"
>
{{formField.name}}
<span v-if="formField.required" class="small"> *</span>
</v-col>
<v-col
md="8"
align-self="center"
class="pl-3"
>
<v-text-field
v-if="formField.type === 'password'"
:id="formField.key"
:key="formField.key"
v-model="formField.value"
:append-icon="showPasswordIcon ? '$vuetify.icons.values.eye' : '$vuetify.icons.values.eyeSlash'"
:type="showPasswordIcon ? 'text' : 'password'"
:hint="getHintText(formField)"
:value="formField.name"
:required="formField.required"
:valid="(!formField.isValid) ? false : undefined"
dense
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
#click:append="showPasswordIcon = !showPasswordIcon"
/>
<v-text-field
v-if="formField.type === 'text'"
:id="formField.key"
v-model="formField.value"
dense
:valid="(!formField.isValid) ? false : undefined"
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
/>
<v-checkbox
v-if="formField.type === 'boolean'"
:id="formField.key"
v-model="formField.value"
class="mt-2"
/>
<v-text-field
v-if="formField.type === 'number'"
:id="formField.key"
v-model.number="formField.value"
dense
:valid="(!formField.isValid) ? false : undefined"
class="mb-0"
type="number"
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
/>
</v-col>
</v-row>
</template>
</div>
</template>
Thank you so much for any tips on this!
Easiest solution might be to add an extra property to each element in the formFields, like visible, that tracks if a password should show its text. You can do that on API response and then insert it.
Then in your loop you can do
:type="formField.visible ? 'text' : 'password'"
This way, every formField is responsible for their own password visibility.
Next, you change
#click:append="showPasswordIcon = !showPasswordIcon"
to
#click:append="toggleShowPassword(formField.key)"
toggleShowPassword(key){
let formfield = this.formfields.find(x => x.key === key)
if(formfield){
formfield.visible = !formfield.visible
}
}
That should work!

How to reset v-model after hiding input with conditional rendering

I have two inputs from which the first one is a switch and the second one is a text field which gets conditionally displayed if switch is set to true.
In situation when user sets the switch to true and then enters something in the text box the v model value for this input needs to be reset / removed when user sets the switch to false again.
I know I can achieve this manually or by using watcher. However just curious if I have missed something in the docs which will do this for me or may be a better method than what I think is the only way.
<v-row>
<v-col cols="12" sm="12">
<v-switch
v-model="data.budget_confirmed"
label="Budget Confirmed"
color="primary"
class="ma-0 pt-0"
hide-details
/>
</v-col>
<v-col v-if="data.budget_confirmed === true" cols="12" sm="12">
<validation-provider v-slot="{ errors }" name="Amount" rules="required">
<v-text-field
v-model="data.amount"
name="amount"
label="Amount"
:error-messages="errors"
:hide-details="!errors.length"
outlined
dense
/>
</validation-provider>
</v-col
</v-row>
Listen for the change event on the switch:
<v-switch
v-model="data.budget_confirmed"
label="Budget Confirmed"
color="primary"
class="ma-0 pt-0"
hide-details
#change="onSwitchToggle"
/>
Then in the onSwitchToggle method, reset amount when the switch if off:
onSwitchToggle () {
if (!this.budget_confirmed) {
this.amount = 0;
}
}

v-slot:badge and v-if does not work with a computed property

I'm working on a CMS project and I have an issue I can't figure out.
I Have a component where I'm showing IP's. On change I want a badge to appear, so the user knows "this field is changed".
But the thing is the badge won't show if I'm using "v-slot:badge".
In the v-if is a computed property, If I inspect the page with vue devtools ‘isStartIpValueChanged’ will be true on a change. So, it should work right?
Template
<v-list-item-content>
<v-form ref="form" v-model="valid">
<v-hover v-slot:default="{ hover }">
<v-row align-content="center" no-gutters>
<v-col>
<v-badge overlap color="red" right>
<template v-slot:badge v-if="isStartIpValueChanged">
<v-avatar color="red" size="6"></v-avatar>
</template>
<v-text-field
dense
:rules="apiIpRules"
v-model="apiIp.startIp"
#input="valueChanged()"
ref="startIp"
:class="hover ? 'hover-text-color' : ''"
placeholder="###.###.###.###">
</v-text-field>
</v-badge>
</v-col>
<v-col cols="1" class="text-center" align-self="center">
<p>-</p>
</v-col>
<v-col cols="1" class="text-center" align-self="center">
<v-btn v-show="hover" #click="deleteIp()" icon small color="red"><v-icon>mdi-minus-circle</v-icon></v-btn>
</v-col>
</v-row>
</v-hover>
</v-form>
Created and Computed (apiIp is a prop I get from the parent component)
created () {
this.apiIpsOriginalValueStartIp = this.apiIp.startIp
this.apiIpsOriginalValueEndIp = this.apiIp.endIp
this.apiIp.uuid = this.GenerateUUID()
},
computed: {
isStartIpValueChanged () {
return this.apiIp &&
(this.apiIp.startIp !== this.apiIpsOriginalValueStartIp ||
this.apiIp.uuid === null)
},
isEndIpValueChanged () {
return this.apiIp &&
(this.apiIp.endIp !== this.apiIpsOriginalValueEndIp ||
this.apiIp.uuid === null)
}
},
Anyone know what is going wrong here?
As according to Vuetify's own documentation, you should be using the v-model, directly on the v-badge, to show it only when you want it to.
<v-badge overlap color="red" right v-model="isStartIpValueChanged">
<template v-slot:badge>
<v-avatar color="red" size="6"></v-avatar>
</template>
<v-text-field
dense
:rules="apiIpRules"
v-model="apiIp.startIp"
#input="valueChanged()"
ref="startIp"
:class="hover ? 'hover-text-color' : ''"
placeholder="###.###.###.###">
</v-text-field>
</v-badge>
Doc: https://vuetifyjs.com/en/components/badges#show-on-hover

Getting "Cannot read property 'key' of undefined" in vue template

So in my vue I have a method that takes some data, creates arrays and passes them to another vue file for rendering in the template.
The method
this.shoesData.titles = ['Date', 'Model', 'Price Qty', 'Order Qty', 'Discount Qty'];
this.shoesData.values = [
new Date(this.getShoes.insertDate).toISOString().slice(0, 10).toString(),
this.getShoes.model,
parseFloat(this.getShoes.price).toFixed(0).toString()+' tn',
parseFloat(this.getShoes.order).toFixed(0).toString()+' tn',
parseFloat(this.getShoes.discount).toFixed(0).toString()+' tn'
];
and then I pass shoesData to another file to use it in its template
<CardMultiValue v-if="shoesData.values" :cardData="shoesData" />
in CardMultiValue I have,
<template>
<v-card style="width:100%;height:100%;" :flat="flat" >
<v-card-title class="title" v-if="cardData.Title" style="width:100%;height:30px;justify-content:center;align-items:center;padding:5px;">{{cardData.Title}}</v-card-title>
<v-card-actions v-if="cardData.Title" style='width:100%;height:calc(100% - 30px);padding:5px;' >
<v-container style="padding:0px;height:100%;">
<v-row style="height:100%;">
<v-col :cols="8">
<div v-for="title in cardData.titles" :key="title" :style="'display:flex;align-items:center;font-size:18px;font-weight:bold;height:'+rowHeight+'%;'">
{{title}}
</div>
</v-col>
<v-col :cols="4">
<div v-for="value in cardData.values" :key="value" :style="'display:flex;align-items:center;font-size:18px;height:'+rowHeight+'%;'">
{{value}}
</div>
</v-col>
</v-row>
</v-container>
</v-card-actions>
<v-card-actions v-else style='width:100%;height:100%;padding:5px;' >
<v-container style="padding:0px;height:100%;">
<v-row style="height:100%;">
<v-col :cols="8">
<div v-for="a in cardData.titles" :key="a" :style="'display:flex;align-items:center;font-size:18px;font-weight:bold;height:'+rowHeight+'%;'">
{{a}}
</div>
</v-col>
<v-col :cols="4">
<div v-for="b in cardData.values" :key="b" :style="'display:flex;align-items:center;font-size:18px;height:'+rowHeight+'%;'">
{{b}}
</div>
</v-col>
</v-row>
</v-container>
</v-card-actions>
</v-card>
This is not something complicated, and yet, if this.getShoes.order and this.getShoes.discount both happen to be 0 , I get
TypeError: Cannot read property 'key' of undefined
at sameVnode (vue.runtime.esm.js?2b0e:5811)
at updateChildren (vue.runtime.esm.js?2b0e:6213)
at patchVnode (vue.runtime.esm.js?2b0e:6313)
at updateChildren (vue.runtime.esm.js?2b0e:6187)
at patchVnode (vue.runtime.esm.js?2b0e:6313)
at updateChildren (vue.runtime.esm.js?2b0e:6187)
at patchVnode (vue.runtime.esm.js?2b0e:6313)
at updateChildren (vue.runtime.esm.js?2b0e:6187)
at patchVnode (vue.runtime.esm.js?2b0e:6313)
at updateChildren (vue.runtime.esm.js?2b0e:6187)
This must be a template error, because if I completely remove this.getShoes.order or this.getShoes.discount I get no error. Also, if I dont pass the data to CardMultiValue I get no error.
How can I fix this? Thanks
this.getshoes sounds like a method name. So, perhaps change it to this.getShoes().price or pass the appropriate paramters, if there are any, to it; this.getShoes(someParameter).price