VueJs 2 - Force Checkbox DOM value to respect data value - vue.js

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

Related

By default Checked checkbox using v-model

Hi Guys I'm Newbie at VueJS,
Anyone who can help me about on getting default checked at my checkbox list
I'm using v-model so the checked won't work
Any idea or suggestion?
You bind the input to a truthy value using the v-model directive
<input type="checkbox" v-model="selected">
In your component data (Updated based on #Phil s comment)
data () {
return {
selected: true, // True of false, or other truthy value depending on needs
}
}
Then, depending on the value on selected your input will be checked/unchecked.
Note - in the documents it is stated that
v-model will ignore the initial value, checked, or selected attributes
found on any form elements. It will always treat the Vue instance data
as the source of truth. You should declare the initial value on the
JavaScript side, inside the data option of your component.
Read more at https://v2.vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components

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.

How to bind custom event handler from vue-touch-events to a custom component in Vue.js

I'm currently implementing a classical Minesweeper game in Vue.js which is working fine so far https://github.com/franktopel/defuse, Demo http://connexo.de/defuse/.
Now I would like to add touch support because as of now, to mark a field as "contains a mine" it is required that you right-click the field. Right-clicking is obviously not available on touch devices, so I would like to add longtap support. I'm using native events click and click.right from the parent component for each field, so the field does not handle the events, but the parent component that instantiates these fields does.
I've found this https://github.com/jerrybendy/vue-touch-events and added it to my project, yet it seems I cannot use this on the component tag (see https://github.com/franktopel/defuse/blob/master/src/components/Defuse.vue):
<m-field
v-for="field in row"
:field="field"
:key="`${field.x},${field.y}`"
#click.native="open(field)"
#click.right.native.prevent="toggleBombMarker(field)"
v-touch:longtap="toggleBombMarker(field)"
></m-field>
because that marks all fields without any user interaction and the console keeps producing
You may have an infinite update loop in a component render function.
This is how my field objects (which I'm passing to the field component) are created:
let Field = function (x, y) {
this.x = x
this.y = y
this.isOpen = false
this.hasBomb = false
this.isMarked = false
this.numNeighbourBombs = null
}
module.exports = Field
I have also tried emitting a custom event from inside my field component, yet I don't know how I can pass the triggering field to the event handler from there.
Can anyone push me in the right direction?
According to the vue-touch-events docs, the v-touch directive doesn't work in the same way as v-on; v-touch must be given a function to execute, whereas the toggleBombMarker(field) expression probably returns undefined.
If you want to pass extra parameters to the v-touch handler, your handler must return a function like this:
methods: {
toggleBombMarker(field) {
return () => {
// your handler code here
}
}
}

VueJS - Adjusting property from method does not update the view

I'm using the Vue Multiselect component, along with a list that displays suggested items.
I've basically got
selectedItems: []
allItems: []
onSelectOfItem(item) {
item.selected = true;
}
My HTML has the #select="onSelectOfItem" event which fires when multiselect picks an item, and it passes in the item.
I've also got a list of suggested items thats like
<li v-for="item in allItems" v-if="!item.selected"></li>
However when the onSelectOfItem method fires and I assign selected = true the v-for I have does not hide the item, however if I use the vue debug tools and inspect the data selected is set to false
If i add a #click="onSelectOfItem(item)" to the repeater, it works fine.
Id expect that changing the value on the object would update throughout, I'm from an Angular background which passes everything by reference, so no matter where i update item.selected from the whole UI will be in sync.
Why is the UI not reacting to the change within the object?? and how can I fix.
Thanks

Aurelia: Programmatically changing reference value doesn't change model

We have a situation where we utilize a component in multiple web pages (a note editor). This note editor takes a value from an input element on the page and places that value into a component where the user can modify it. The user types in the note editor and clicks Submit. The note editor component then passes the new value back to the input on the original page.
We are using the "ref" to pass the value back and forth. Everything works fine except that the model doesn't update when we set the value of the ref from the note editor component. We find we need to type once in order for it update the model. Here is a simple Gist to illustrate our example:
This is just a simple example of programmatically setting the ref's value.
Note how "The value of my input is" stays as "Hello" but the input field changes to "Value Changed!!!!" when you press the button.
https://gist.run/?id=fab025d6b99a93f9951b1a6e20efeb5e
A few things to note:
1) We'd like to use Aurelia's "ref" instead of an "id" or "name".
2) We've tried to pass the model instead of the "ref". We can get the value of the model successfully and put it in the note editor, but the model doesn't update when we pass it back.
UPDATE:
We have an answer (thanks!). Here is the code we tried to pass the model (so we wouldn't even need to use the ref). This failed for us.
Here is the View of the page.html
<TextArea value.bind="main.vAffectedClients" style="width:94%;" class="editfld" type="text" rows="6"></TextArea>
<input class="butn xxsBtn" type="button" value="..." click.trigger="OpenNoteDivAurelia(main.vAffectedClients)" />
Here is the View-Model of the page.js
import {NoteEditor} from './SmallDivs/note-editor';
...
#inject(NoteEditor, ...)
export class PageName {
constructor(NoteEditor, ...)
{
this.note = NoteEditor;
...
}
OpenNoteDivAurelia(myTargetFld)
{
this.note.targetFld = myTargetFld;
this.note.vHidTextArea.value = myTargetFld;
this.note.show();
}
}
This part opens our component (note-editor) and successfully places the targetFld value inot our TextArea in the component.
Here is the View-Model when placing the value BACK to page.js/page.html
CloseNote(populateFld)
{
if (populateFld)
{
//This is the line that doesn't seem to work
this.targetFld = vHidTextArea.value;
}
this.isVisible = false;
}
This last function "CloseNote" is the one that doesn't work. The model (which we believe is pointed at this.targetFld) does not get the value of the textarea. It does not error, it simply does not do anything.
The events that Aurelia attaches to be notified of an input changing don't fire when you programmatically set the value property on an input. It's simple enough to fire one of these events yourself, though.
export class App {
mymodel = {"test":"Hello"};
changeValByRef(myinput)
{
myinput.value = "Value Changed!!!!";
myinput.dispatchEvent(new Event('change'));
}
}
You actually don't need to pass the ref in to the function, anytime you use the ref attribute, a property is added to your VM w/the name you use in the ref attribute. So the above example could have been accomplished using this.myinput instead of the passed in object, since they're the same.
Here's a working example: https://gist.run/?id=7f96df1217ac2104de1b8595c4ae0447
I'd be interested to look at your code where you're having issues passing the model around. I could probably help you figure out what's going wrong so you don't need to use ref to accomplish something like this.