euvl/vue-js-toggle-button

Button gets "out of sync"

Closed this issue · 8 comments

Hello,

I use this button to trigger an offer publication status.
So when I use this button, it calls an API to change the state of the publication.

If an errors occurs, it should revert the button to initial position, except it does not.
Please help me out, thanks.

      switchActiveState(offer) {
        console.log(offer.active);  // returns true in this example
        const matchItem = collection.find(this.items, item => item.id === offer.id);
        if (matchItem) {
          axios
            .post('/switch-status....')
            .then((response) => {
              if (response.data.success === true) {
                matchItem.active = response.data.status;
              } else {
                // if we get anything but success true, we change the value back to initial
                matchItem.active = offer.active;
              }
            })
            .catch(() => {
              // if we get any error, we change the value back to initial
              matchItem.active = offer.active;
            })
          ;
        }
      },
<template slot="status" slot-scope="slotProps">
          <toggle-button
            @change="switchActiveState(slotProps.item)"
            :value="slotProps.item.active"
            color="#20aec4"
            :sync="true"
            :labels="false"
          />
</template>

Result in screenshot, after clicking, the active on the object is still true, because there were an error:
plein_ecran_16_12_2017_12_04

BUT the button is "false" instead of true as if the offer is not published.
metadata_title_recruitment_center_team

What am I missing there ?

I wanted to ask the same question. I find the same problem and I don't know why :(

euvl commented

try caching offer.active rather than directly using it by reference.

Mhh, not sure If I understand you correctly, I tried:

      switchActiveState(offer) {
        console.log(offer, offer.active);
        const matchItem = collection.find(this.items, item => item.id === offer.id);
        if (matchItem) {
          axios
            .post(this.getSwitchRouteFor(offer))
            .then((response) => {
              if (response.data.success === true) {
                offer.active = response.data.active;
              } else {
                offer.active = offer.active;
              }
            })
            .catch(() => {
              offer.active = offer.active;
            })
          ;
        }
      },

Without any difference.
When it fails, the switch-button still act as if everything were normal, and it's not reverting

euvl commented

Try this out of interest:

  switchActiveState: offer => {
    const cachedActive = offer.active
    const matchItem = collection.find(this.items, item => item.id === offer.id)
    if (matchItem) {
      axios
        .post('/switch-status....')
        .then(response => {
          if (response.data.success) {
            matchItem.active = response.data.status
          } else {
            matchItem.active = cachedActive
          }
        })
        .catch(() => {
          matchItem.active = cachedActive
        })
    }
  },

When trying your version, it gives:
[Vue warn]: Error in event handler for "change": "TypeError: undefined has no properties"

And when trying to fix it by putting :
switchActiveState(offer) {

It's the same behaviour like before. Even when I do this:

switchActiveState(offer) {
  offer.active = true; 
} 

or

switchActiveState(offer) {
  const matchItem = collection.find(this.items, item => item.id === offer.id);
  matchItem.active = true;
} 

The button still act on it's on toggling on and off instead of being forced to be "on" all the time. (because of the .active = true)

@euvl Full code can be found here if it helps you understand what's wrong, it's the <toogle-button> on L58 that i'm reffering to.
https://gist.github.com/tristanbes/bf3ff71f4c091693382f05abfdd9eea5

thanks to @Kocal, the working example is:

switchActiveState(offer) {
        const wasActive = offer.active;
        offer.active = !wasActive;
        this.$set(offer, 'toggling', true);
        axios
          .post(this.getSwitchRouteFor(offer))
          .then((response) => {
            offer.active = response.data.success === true ? response.data.active : wasActive;
          })
          .catch(() => {
            offer.active = wasActive;
          })
          .finally(() => {
            this.$delete(offer, 'toggling');
          });
      },

I just get the same problem and fixed it.

If you use it inside looping, you should add prop :key to the toggle button