vue-js-toggle-button icon indicating copy to clipboard operation
vue-js-toggle-button copied to clipboard

v-model is confusing

Open JelledFro opened this issue 6 years ago • 14 comments
trafficstars

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.

JelledFro avatar Jul 22 '19 13:07 JelledFro

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

adam-godfrey avatar Oct 29 '19 08:10 adam-godfrey

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

euvl avatar Oct 29 '19 22:10 euvl

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

vesper8 avatar Nov 03 '19 23:11 vesper8

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 ?

ButeForce avatar Dec 20 '19 19:12 ButeForce

yes it's working fine for me now using v-model

maybe post your code if you're having trouble?

vesper8 avatar Dec 20 '19 20:12 vesper8

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:

{ `

{{control.control_name}}

`

}

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 );

}

}

ButeForce avatar Dec 20 '19 20:12 ButeForce

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>

ButeForce avatar Dec 20 '19 20:12 ButeForce

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>

vesper8 avatar Dec 20 '19 21:12 vesper8

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.

ButeForce avatar Dec 21 '19 07:12 ButeForce

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.

ButeForce avatar Dec 21 '19 11:12 ButeForce

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

vesper8 avatar Dec 21 '19 12:12 vesper8

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>

Aymkdn avatar Apr 24 '20 12:04 Aymkdn

This must fix:

<toggle-button v-model="myData" sync></toggle-button>

evsar3 avatar Jun 06 '20 19:06 evsar3

https://github.com/euvl/vue-js-toggle-button/issues/115#issuecomment-640107498 could close the issue.

hobbydev71 avatar Sep 29 '21 23:09 hobbydev71