Vuetify Select Retaining old value - vue.js

I've got a Vuetify select, with the following syntax.
<v-select label="..." autocomplete
append-icon="search" :items="plots" item-value="id" item-text="plotHeader"
v-model="selectedPlot" v-on:change="loadPlotInformation();">
</v-select>
So when the page loads, the dropdown initializes with an Ajax request. But when the user changes the value, the model reflects the old value, not the current selection.
Inside the function.
loadPlotInformation() {
console.log(this.selectedPlot);
}
Update:
I was able to fix the issue by transitioning to blur event. But why would change event not resolve?

If you want to take new value instead of the old value, you should use nextTick method.
eg:
loadPlotInformation() {
this.$nextTick(() => {
console.log(this.selectedPlot);
})
};

Try to change your function to read the parameter of your function.
loadPlotInformation(e) {
console.log(e);
}
But this way you need to check if you want to update your model variable

Related

bootstrap-vue table, Formatter callback error: You may have an infinite update loop in a component render function

I'm using bootstrap-vue table, according to documentation regarding formatter callback: https://bootstrap-vue.org/docs/components/table .
A variable is defined in data(), I will need this variable as a flag to control the cell content.
data() {
return {
aFlag: 0,
}
}
Then in the fields I use the formatter call back:
{ key: 'value', label: 'Value', formatter: this.updateValue},
In the methods area I use updateValue to update the flag:
methods: {
updateValue(value) {
..
aFlag = value
..
}
}
Then error "You may have an infinite update loop in a component render function." happened here.
If I want to do such a thing, is there any best practice? The cell content may cause other cell's change, so currently I use a variable to control the behavior as a flag. Thanks in adavance.
The formatter callback is only intended to change how the value is displayed to the user, not change its value.
If you want to be able to change the value, I'd suggest using a slot for the value property and use v-model on a form component within the slot:
<template v-slot:cell(value)="data">
<input type="text" v-model="data.value"/>
</template>

Quasar: Is there any way to get the value typed into a QSelect with use-input before it gets removed on blur?

Per the docs you can add the attribute use-input to a QSelect component to introduce filtering and things of that nature: https://quasar.dev/vue-components/select#Native-attributes-with-use-input.
However, if you type something into one of these fields and click outside of it, the text gets removed.
Is there any way to grab that text in Vue before it gets removed and do something with it?
Since v1.9.9 there is also a #input-value event described in the q-select api.
As the api says it's emitted when the value in the text input changes. The new value is passed as parameter.
In the examples there's a filter function, so there you can save it in a data variable:
methods: {
filterFn (val, update, abort) {
update(() => {
this.myDataVariable = val;
})
}
}

How to use Vue v-model binding in Vuetify components together with computed properties and Vuex?

I'm trying to use v-radio-group in conjunction with computed values from Vuex as described similarly here.
Example codepen of the issue I'm facing is here
Whenever a radio button is clicked, a Vuex mutation is called to save the selected value in the state.
However it can be the case that some validation fails inside the mutation and that therefore the value is not changed in the state as expected.
Regardless of what value ends up in the Vuex state, the radio buttons do not truly reflect the current state.
E.g. in the codepen snippet I'd expect the second option (Option 1) never to show as chosen, as the corresponding state is always 0.
As far as I can see this behavior is not only happening when using v-radio-groups.
It happens with all Vuetify components using v-model and computed getters/setters.
So e.g. Vuetifys v-text-input/v-text-field and v-select also show the same behavior.
To sum it up, my questions are the following:
Why is the second option in my codepen example getting selected even as the corresponding state is different?
How can I achieve the expected result (Having Option 1 never shown as selected, even when it is clicked)?
As far as I know Vuetify keeps its own state in their components like v-radio-group.
To change it you need to send updated props. Then it will react and update its own state.
The trouble is that you are performing validation in a mutation. Which is a bad practice in my opinion.
I will show you how to "block" changing state and update v-radio-group so its own state corresponds to what is actually in your $store.state.radioState.
And I will spend some more time to figure out how to performe it in on mutation ;-)
This is not a perfect solution >> my codepen
Your mutation just updates the state.
// store.js
mutations: {
setRadioState (state, data) {
state.radioState = data;
},
},
Your set method do the validation.
// component
computed: {
chosenOption: {
get () {
return this.$store.state.radioState;
},
set (value) {
if (value !== 1) {
this.$store.commit('setRadioState', value)
} else {
const oldValue = this.$store.state.radioState
this.$store.commit('setRadioState', value)
this.$nextTick(() => {
this.$store.commit('setRadioState', oldValue)
})
}
}
}
}
What happens in the set when it fails validation? You save current state to oldValue, you update state so it corresponds to v-radio-group component. And in the $nextTick you change it right back to oldValue. That way v-radio-group gets updated props and change its state to yours.

Updating the values sent to child component on user click in vuejs

I have two components in mu app.vue and i will send data from app.vue to my first component(filter component) at the time of page load.
Now based on the user actions in the displayed data in the second component i need to pass new vales back to the first component.
There i am using a and a . Consider one of the props i receive in the first component is "nselectedOption" and i do this in data: { return { selectedOption: this.nselectedOption }} to avoid mutation warning.
Now everytime i update the values for this component from second component, i am seeing changes in "nselectedOption" only and not in "selectedOption". Can you explain why is that ?
I need the updated value into a v-model of .
1. If i use "nselectedOption" it is updating the textbox but while editing the value throws error.
2. If i use "selectedOption" it is not updating the values in the textbox itself.
I have even tried using the computed values to return the value, it works but if i try to change values in other options in the filter component the already updated values displays null or nothing.
Please help me. Is this problem can be solved using State Management Concept or do i have to have a separate compoenent other than App.Vue to do all this so that it would act as a parent/child kinda thing or is there anyother way to overcome this.
Try using watcher. If you watch for nselectedOption, everytime it changes, the watcher will fire and bind the changed value to selectedOption.
props: ['nselectedOption'],
data: {
selectedOption
},
watch: {
nselectedOption: function (val) {
this.selectedOption = val
}
}
Also, if the prop you are watching is an object/array, consider using spread operator if you want to make a local copy to avoid mutation.
this.someObj = { ...someProp }

How to get Vuetify checkbox event.target.checked and event.target.value?

How to get Vuetify checkbox event.target.checked and event.target.value?
I'm using Vuetify's checkbox in my app. When the user checks/unchecks it, I want to get the checked and the value properties.
I realize that it is not a native checkbox element, so I don't have access to event.target.checked or event.target.value, but surely there must be a way to do that. I tried the following:
<p v-for="(linkType, index) in linkTypes" v-if='linksLoaded'>
<v-checkbox
color="info"
:label="linkType"
:value="linkType"
v-model="checkedLinks"
#click="onCheckboxClicked($event)"></v-checkbox>
</p>
...
onCheckboxClicked: function(e) {
console.log(e);
},
For some reason it printed a mouse event TWICE and the checkbox itself didn't change (the check mark wasn't unchecked).
#click.native printed the same mouse event, but once.
I tried #change="onCheckboxClicked" - that printed the v-model.
So is there a way to do that?
I see that you are looping without binding a key, and inside you have v-model which is hooked to a single variable. So, whenever some checkbox is changed all others will update simultaneously. So you need new v-model for each checkbox. Why not add another property in linkTypes so you can v-model="linkType.checked".
change is the name of the event which gets triggered whenever checkbox value is changed and value is passed as a parameter.
<v-checkbox
#change="checkboxUpdated"
color="info"
:label="linkType"
:value="linkType"
v-model="checkedLinks"
#click="onCheckboxClicked($event)"></v-checkbox>
and in methods you need
checkboxUpdated(newValue){
console.log(newValue)
}
The easy way to access whether the checkbox is checked or not after clicking is to check it value. If it is null or empty array, then you can assume that its not checked. It depends on how you initialised the variable. This is the safest way to get what you want.
<v-checkbox
v-for="(el, index) in checkboxes"
:key="index"
v-model="checkbox[index]"
:value="el"
:label="`Checkbox ${index}`"
#change="valueChanged($event, index)"
></v-checkbox>
new Vue({
el: '#app',
data () {
return {
checkboxes: ['Opt 1', 'Opt 2', 'Opt 3', 'Opt 4'],
checkbox: [],
}
},
methods: {
onChange(val, i) {
console.log(val, i, this.checkbox)
if (val === null || val.length === 0) { // Custom checks in this
console.log('Unchecked')
} else {
console.log('Checked')
}
}
}
})
If you really need access to the element, then you can use ref to get the component. Then try to find the input element inside the component. And then find the checked value of that input element. But depending on how the library is implemented, you might not get the right value for $refs.checkbox.$el.target.checked.
You are lookin for a event. If you want to know if your checkbox is checked or not, you should use this:
onCheckboxClicked: function(e) {
console.log(e.target.checked)
},
As you've already noticed, Vuetify checkbox is not a native checkbox element. Therefore, event.target.checked and event.target.value do not exist. To fix this, one needs to do 2 things:
Disable the ripple effect of the v-checkbox. Otherwise, there will be a div on top of the input checkbox tag. Then, event.target is the one we expected.
However, when the user clicks on the label, it also affects the checkbox. In this case, we need to access the checkbox via event.target.control.
The checkbox in your question should like this:
<v-checkbox
color="info"
:ripple="false"
:label="linkType"
:value="linkType"
v-model="checkedLinks"
#click.native="onCheckboxClicked"
/>
Then, in the onCheckboxClicked method:
const onCheckboxClicked = (event) => {
const target = event.target.control ?? event.target;
const isChecked = target.checked;
const value = target.value;
// Do something here...
};
Notice that we use .native modifier for the click event. Otherwise, the event.target.control.checked will give opposite values (false when the checkbox is checked and vice versa).
And small note: you should always bind the key value when using v-for.