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

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.

Related

Vuetify Combobox not updating to correct value

I have a Vuetify combobox that on save does an api call to store the selected or entered value. However, when updating this value, if the save button is clicked directly without deselecting the combobox, the previously stored value is stored again, instead of the new value. Only when I manually unselect the box or press enter does the correct value store. I have looked around and found certain fixes that have worked for others, such as .blur() and .$nextTick, but they haven't seemed to work for me (I could be implementing them incorrectly). Here's what I have:
Combobox:
<v-combobox
:items="suggestions"
v-model="editedItem.field_label"
label="Label"
outlined
dense
ref = "comboBox"
></v-combobox>
Save button:
<v-btn color="blue darken-1" text #click="save"> Save</v-btn>
Save function:
save() {
this.$refs.comboBox.$emit("blur")
this.$nextTick(() => {
const device_field = {
...this.editedItem,
};
device_field_api
.updateDeviceField(device_field, this.device_id)
.then((r) => {
//Various logging items
);
})
.finally(this.initialize())
.catch((e) => {
//Error catching
);
});
});
}
Change
this.$refs.comboBox.$emit("blur")
to this:
this.$refs.comboBox.blur().
Codepen example
Result:

VueJs 2 - Force Checkbox DOM value to respect data value

I cannot for the life of me figure this out.
Fiddle at: https://jsfiddle.net/s8xvkt10/
I want
User clicks checkbox
Then based on separate conditions
Checkbox calculatedCheckedValue returns a data property /v-model of true/false
And the checked state reflects the calculatedCheckedValue
I can get:
The calculatedCheckedValue calculates and interpolates properly
But I fail at:
Having the :checked attribute render the calculatedCheckedValue properly in the DOM
e.g. If a false checkbox is clicked and the calculatedCheckedValue still returns false, the checkbox toggles onscreen between checked and unchecked
I’ve tried:
Using a v-model with a custom set that does the calculation and sets the local state which the custom get returns
Imitating a v-model using #change.prevent.stop="updateCalculatedValue" and :checked="calculatedValue"
Assuming the #change happens after the #click (which i think is wrong) and using #click.prevent.stop="updateCalculatedValue" and :checked="calculatedValue"
The model is working and rendering the calculated value as string in a DOM span,
but the checked value doesn't seem to respect the model value
Can someone please help me out?
I've solved the problem at: https://jsfiddle.net/pc7y2kwg/2/
As far as I can tell, the click event is triggered even by keyboard events (src)
And happens before the #change or #input events (src)
So you can click.prevent the event, but you need to either prevent it selectively or retrigger the event after the calculation.
//HTML Template
<input :checked="calculatedValue5" #click="correctAnswer" type="checkbox">
//VUE component
data() {
return {
calculatedValue5: false,
};
},
methods: {
correctAnswer(e){
const newDomValue = e.target.checked;
this.calculatedValue5 = this._calculateNewValue(newDomValue);
if(this.calculatedValue5 !== newDomValue){
e.preventDefault();
}
}
}
I think this is preventing checkbox value from updating before the data value, which seems to break the reactivity. I'm not sure the technical reason why, but the demo does work

v-select on close event or remove validation error timer?

Final Edit/Solution: https://jsfiddle.net/up9xkhsm/1/
Is there such an event for v-select that I can key on when it is closed? Or some sort of a 'timer' I can set to remove validation errors after they occur?
This is the v-select I am using:
https://vuetifyjs.com/en/components/selects
Edit: this outlines the issue:
https://jsfiddle.net/96vnLm7g/
I want to know when a user clicked on the v-select but did not select anything. It has to be possible, obviously, since the validation can pick up on this..
Use an onChange prop to add your callback function, so you can check for the v-model assigned to v-select if has changed, to clear the validation errors. Or watch the v-model assigned to v-select for changes.
Using onChange:
<v-select :options="options" :on-change="cleanUpValidation" v-model="selectModel" name="some-select"></v-select>
And in VueJS
methods: {
cleanUpValidation(){
//do the cleanup
}
}
By default, onChange emits input event with value of selected option:
default: function (val) {
this.$emit('input', val)
}
So you can use it also to catch the input event:
<v-select :options="options" #input="cleanUpValidation" v-model="selectModel" name="some-select"></v-select>
In VueJS
methods: {
cleanUpValidation(val){
//do something with selected option value or cleanup error
}
}
Or you can watch the model assigned to v-select:
watch: {
'selectModel' : function(){
//do the cleanup or something with this.selectModel
}
}
For onChange and other props see:
https://sagalbot.github.io/vue-select/docs/Api/Props.html
Same thing would apply for VuetifyJS's v-select.
Edit:
Main goal was to clear validation errors when v-select is actually clicked.
v-select uses focus event within its onClick() method, to tell the VueJS that component is clicked, so that can be used to catch the click event:
<v-select
#input="inputChanged"
v-on:change="changeChanged"
label="Select Item"
:items="myItems"
required
:rules="rules.requiredField"
#focus="focusChanged"
>
</v-select>
And in js:
methods:{
focusChanged(){
console.log('focusChanged ');
},
}
For last example: https://jsfiddle.net/c5moqweu/
And see https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VSelect/VSelect.js
onClick
Method

Vuetify Select Retaining old value

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

Vue wrapper example

There are a good examples of integrating vue with select2.
I have a question.
If we look at this part of the code:
mounted: function () {
var vm = this
$(this.$el)
// init select2
.select2({ data: this.options })
.val(this.value)
.trigger('change')
// emit event on change.
.on('change', function () {
vm.$emit('input', this.value)
})
}
I don't understand, why when we change value of select2, this.value changes too.
I expected a record like:
.on('change', function () {
this.value = $(this.$el).val()
vm.$emit('input', this.value)
})
It behaves that way because of how v-model works. What you are a looking at is a 2-way binding. Where if the value of selected in v-model="selected" changes, the value will be pushed down to the component.
When vm.$emit('input', this.value) is called, it tells the parent to update whatever variable is listening to changes, in this case selected, which it turn gets pushed back to the component such that its value gets changed.
To make it simpler to understand, this is the sequence of events:
select2's value changes
the select2 value change triggers an event emission
the parent receives the event and updates selected
the component's value gets assigned to the new value of selected
the watcher for the value gets triggered and updates select2 with the new value
Good question though.
Caveat: Doing this is understandably poor practice. It will break it sad ways when used with 1-way bindings.
After writing my previous answer, I realized I missed something important: contexts.
On line 5 in the jsfiddle, there is this line:
var vm = this, why?
This is because later on, when doing vm.$emit, this.$emit will not work; the context has been changed.
.on('change', function () {
//this = select2 element
vm.value // == 1
this.value // == 2
vm.$emit("input", this.value);
})
The value on the emit event is not that of the component, but of the select2 element.
While the value has not yet been changed on the component, the new value has been broadcasted to the parent.
Notice how select2 component used in the template:
<select2 :options="options" v-model="selected">
<option disabled value="0">Select one</option>
</select2>
In Vue.js using v-model with components could be simplified to:
<your-component
:value="selected"
#input="value => { selected = value }">
</your-component>
So every time you emit an event from your component the value gets changed at the parent component.
Source