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

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' : ''
}
}

Related

How to prepopulate date range value?

I have an issue on my edit page while trying to prepopulate date range value.
Ex. 2022-06-03, 2022-06-04
Rather than see this
I got an error in the console.
I don't know if I understood the question correctly, but in the absence of a code snippet I refer to the official Vuetify documentation.
Basically you assign a date pattern to the Vuetify component and optionally, with a computed, calculate the divisor.
export default {
data: () => ({
dates: ['2019-09-10', '2019-09-20'],
}),
computed: {
dateRangeText () {
return this.dates.join(' ~ ')
},
},
}
<v-row>
<v-col
cols="12"
sm="6"
>
<v-date-picker
v-model="dates"
range
></v-date-picker>
</v-col>
<v-col
cols="12"
sm="6"
>
<v-text-field
v-model="dateRangeText"
label="Date range"
prepend-icon="mdi-calendar"
readonly
></v-text-field>
model: {{ dates }}
</v-col>
</v-row>

How do I watch for onChange of specific select menu that was dynamically generated?

I have a row of 3 inputs. It lay out like this:
Attribute (select) > Operators (select) > Value (text)
UI look like this:
Code for that:
<v-row v-for="(rule, index) in rules" :key="index">
<v-col cols="12" sm="6" md="3">
<v-select
dense
outlined
item-text="name"
item-value="id"
label="Attribute"
v-model="form.values.attributes"
:items="attributes"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="2">
<v-select
outlined
dense
item-text="name"
item-value="id"
label="Operator"
v-model="rule.operator"
:items="operators"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
dense
outlined
label="Values"
v-model="rule.value"
></v-text-field>
</v-col>
</v-row>
The operator menu is dynamically populated based on API based on the selected attribute.
I have v-model="form.values.attributes", and my watch to call the API for the operators
watch: {
'form.values.attributes'() {
let data = {
$root: 'rules'
}
axios.defaults.headers['Content-Type'] = 'application/json'
axios.post(window.MTS_URL, data).then((response) => {
this.operators = response.data.operators
})
}
}
This works great with one row.
But when I clicked Add, I appended another row, and I need to support multiple rows.
How do I watch for onChange of specific select menu ?
I was thinking to move my
v-model="form.values.attributes"
to
v-model="rule.attribute"
but is it the right thing to do ?
You can try remodeling your data to experience the power of Vue.
Your template:
<template>
<v-app>
<v-row v-for="(rule, index) in rules" :key="index">
<v-col cols="12" sm="6" md="3">
<v-select
dense
outlined
item-text="name"
item-value="id"
label="Attribute"
:items="rule.attributes"
#change="onChange($event, rule, index)"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="2">
<v-select
outlined
dense
item-text="name"
item-value="id"
label="Operator"
:items="rule.operators"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field dense outlined label="Values"></v-text-field>
</v-col>
</v-row>
</v-app>
</template>
Notice how everything is rendered in the rules data. Here the rules data will be an array containing all the rows:
rules = [
{
attributes: ["11", "22"],
operators: []
}
]
Your script should look like below:
<script>
import axios from "axios"
export default {
name: "App",
data() {
return {
rules: [{
attributes: ["11", "22", "33"],
operators: [],
}],
};
},
methods: {
async onChange(changed, rule, index) {
// where:
// `changed` is the value selected
// `rule` is the attributes and rule in the selected row
// `index` is the index in the rules array that just got changed
console.log(changed, rule, index);
const operators = await this.fetchApiData(changed);
this.$set(this.rules, index, { ...rule, operators: operators });
},
},
async fetchApiData(data) {
const response = await axios.post(window.MTS_URL, data);
return response.data.operators;
},
};
</script>
if you want to add more rows, you just need to push an object to the rules data:
this.rules.push({
attributes: ["new attribute 1", "new attribute 2"],
operators: []
})

Vee-validate and vuetify checkbox group with v-for

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 }"
>

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