v-model is confusing
JelledFro opened this issue Β· 14 comments
The component looks and works great, but I found something I think is a bit confusing. I would like to get the initial state from Vuex and set the button to the initial state, then I want to toggle the state with the button and set the new state in Vuex. A simple 2 way binding. v-model is usually great for that, but I found with your component I had to use v-bind, :value & :sync simultaneously for it to work that way. Using just ":value" and ":sync" I couldn't get the button to set the value in my computed property, and using just v-bind I didn't get the initial state. Perhaps you could default ":value" to whatever v-model is and default ":sync" to on to simplify things and make v-model work as most people would probably expect it to? Just a suggestion.
I have the exact same problem.
I am looping over a number of rows and creating a toggle switch for each one and it's not picking up the value from v-model
Yeah, I did this one before v-model for custom components (non DOM inputs) was a thing, and then someone else added support for v-model π Maybe it is time for v2
I thought I was losing my mind just now, the toggle-button worked fine in 4 out of 5 of my components and they all had sync set to false (default) and were using a value from the data directive, initialized from a vuex value.. and I was manually setting the vuex on a @change event... a tedious cycle but I hadn't thought of a better way to do it. But for some reason that I still can't figure out, this one component just would not update the :value no matter what I did !?!
I found this issue here and tried out v-model instead, now I'm able to bind the v-model directly to my vuex value and it works perfectly, and this has allowed me to remove quite a bit of code as a result
unsure why the heck it wasn't working before.. and unsure why you had to jump through several hoops to get yours working with a combination of sync and v-bind
I'm uxing vuex-pathify which may be part of the answer
Hi,
I have the same issue and still cannot resolve it, I can get the state using v-model but cannot set the initial status of the toggle to reflect the actual state of the button .
@vesper8 ,
I didn't get if you managed to solved only using v-model ?
yes it's working fine for me now using v-model
maybe post your code if you're having trouble?
Thank you for your quick response,
below is the code, i tried many possibility but failed to get the initial state and v-model working at the same time:
{
`
`
}
in the script block I'm just using a computed property
computed ()
{
return {
state: false
},
methods : {
async onActivate (controlid, controlname)
{
this.$message(" control id : " + controlid + " controlname : " + controlname + " State: " + this.state );
}
}
I dont know why the template code does not appear above
paste it down.
<div v-for="control in scope.row.controls" :key="control.control_name" > <div><toggle-button :value="control.is_activated" @change="onActivate(control.control_id, control.control_name)" v-model="state" :labels="true" color ='#4AB7BD' width="75" height="25" /> <hr></div> </div>
Hrm well.. I think you're doing something really weird with the computed property.. that's not how you use computed properties. Also, you I think what you want to do is tie the v-model to each of your controls' is_activated. You can't use a single state property for multiple toggle buttons. And that value shouldn't be a computed property anyway.
Here's a small code sample which works perfectly for me, which I believe mimics how you've structured your data. Paste that in and try to learn from it. Hope it helps
Notice how I removed the value
attribute. You shouldn't have to use the value
attribute if you're using v-model
P.S. to display multi-line code on Github you need to wrap it by groups of 3 ticks. So it's 3 tricks, line break, code, line break, 3 ticks
<template>
<div>
<div
v-for="control in scope.row.controls"
:key="control.control_name"
>
<div>
<toggle-button
v-model="control.is_activated"
:labels="true"
color="#4AB7BD"
:width="75"
:height="25"
@change="onActivate(control)"
/>
<hr>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
scope: {
row: {
controls: [
{
control_id: 1,
control_name: 'name 1',
is_activated: false,
},
{
control_id: 2,
control_name: 'name 2',
is_activated: true,
},
],
},
},
};
},
methods: {
async onActivate(control) {
console.log(`Id: ${control.control_id} Name : ${control.control_name} State: ${control.is_activated}`);
},
},
};
</script>
dear vesper8 ,
Appreciate your effort and kindness.
actually what I was hoping to achieve is to have the button reflect initial status by reading control.is_activated "which I'm getting it from back-end server trough graphsql , and its being used through slots in the template" , then whenever the user makes a change it will trigger an action based on the new status.
I was using actually normal data() to return the status but the behavior was the same , I'm able to mach every switch to its status if I'm using control.is_activated , but cannot use v-model at the same time.
in this situation I have two states , one which is the devices currently on "either on or off" and i would like to reflect it once the user loads the page , and one which the user will do "switching on or off by selecting the button" afterward , I thought I can do this using value combined with v-model as the documentations says that value to reflect the initial status of the button.
Here is a little update:
what I had to do is actually to get the initial status and put it in an array for each button which is created dynamically , and assign v-model to that item which will be returned from that array , this way every button will have its own status which is fetched initially from the back end server , when the user changes the status of the button it writes back to the same value in that array, I send this value to the @change event so I can take a decision later what the action will be.
the caveat of this is that i have to create a nested loop to push the new values during loading in another array which make the page little bit slower initially.
but the end result is that I have the status initially reflected into the button and in the same time the user can change this value.
Here is how I handle the exact same situation (having preferences persisted to the backend, then loaded on the front-end, and anytime a user makes a change it gets persisted both on the front and back end).
I use Vuex and vuex-pathify (optional but makes everything cleaner).
On a parent component, prior to loading the component that displays the toggle buttons, I make sure that the preferences have been loaded from my REST API, otherwise I load them and assign them to my Vuex store module. I use vuex-persistedstate plugin to persist the vuex store to localStorage so I don't have to constantly fetch it from the REST API.
Once the preferences are loaded in Vuex, I then load the component displaying the toggle buttons. I only use v-models and I don't need to use a @change event because I bind the v-model directly to my vuex store, which thanks to vuex-pathify handles both getters and setters via the 'sync' function
Then, I add a watcher on the vuex "preferences" object, which contains all the values for all my toggle buttons (and more in my case). In the watcher, whenever any of the preferences change, well the vuex store is automatically updated since it's synced, and then I call a method that does a post to my rest api to make sure the modified preferences are also persisted on the backend
v-model
didn't work for me⦠To make it work I've had to do the below:
<toggle-button :value="myVar" :sync="true" @change="myVar=$event.value"></toggle-button>
This must fix:
<toggle-button v-model="myData" sync></toggle-button>
#115 (comment) could close the issue.