1

I'm using vue-select in my app and am trying to prevent an event handler from firing when the default values are first loaded into the vue-select input.

The component looks like this:

<v-select
    multiple
    v-model="product.recommended_accessories"
    label="name"
    :options="accessoryOptions"
    @input="saveProduct"
    @search="onAccessorySearch">
        <template slot="option" slot-scope="option">
            <h4>{{ option.name }}</h4>
            <h5>{{ option.sku }}</h5>
        </template>
</v-select>

As you can see, I want to save the product when the user changes the values in this multi-select. It works fine, but with one issue.

The value of the select is tied to the product.recommended_accessories data. Elsewhere in the app, a product is loaded from the server, which includes a recommended_accessories attribute. Loading the product then triggers saveProduct to be called since vue-select set the preselected options for the input, which apparently triggers the @input event.

Is there anyway around this? Maybe I have made some sort of design error here. Or maybe there is a hook I should be using to bind the event handler, or to set some sort of flag indicating that the product is in the process of being loaded and saving the product shouldn't occur.

I'm just trying to avoid saving the product immediately after it's loaded for no reason.

2 Answers 2

2

For now I am just tracking an accessoryEventCount variable that gets initialized to 0 whenever a product is loaded. Then I make sure accessoryEventCount > 0 before calling saveProduct on an v-select input event.

It works, but I am still wondering if there is a more elegant solution.

UPDATE

Looks like Vue.nextTick is what I was looking for. Before setting the value of product in code, I set a flag this.isSettingProduct = true. Then I set the product, and call Vue.nextTick(() => { this.isSettingProduct = false });.

Now I can avoid saving the product if this.isSettingProduct == true. Using Vue.nextTick ensures that the flag isn't set back to false until after the asynchronous data update completes.

Sign up to request clarification or add additional context in comments.

Comments

0

It looks you should bind prop=onChange, though @input still seems working (check v-select github: line# 544).

Below is my solution, before loading your product, bind onChange with function () {}, after loaded, bind it with the function you like.

Vue.component('v-select', VueSelect.VueSelect)

app = new Vue({
  el: "#app",
  data: {
    accessoryOptions: [
      {'name':'a1', 'sku':'a2'},
      {'name':'b1', 'sku':'b2'},
      {'name':'c1', 'sku':'c2'}
    ],
    product: {
      recommended_accessories: []
    },
    saveProduct: function (){}
  },
  methods: {
    onAccessorySearch: function () {
      console.log('emit input')
    },
    loadProduct: function () {
      this.product.recommended_accessories = ['a1', 'b1'] // simulate get data from the server
      setTimeout( () => {
        this.saveProduct = (value) => {
          console.log('emit input', this.product.recommended_accessories)
        }
      }, 400)
    }
  }
})
#app {
  width: 400px;
}
<script src="https://unpkg.com/vue@latest"></script>
<script src="https://unpkg.com/vue-select@latest"></script>
<div id="app">
  <button @click="loadProduct()">Click Me!</button>
  <v-select
      multiple
      v-model="product.recommended_accessories"
      label="name"
      :options="accessoryOptions"
      :on-change="saveProduct"
      @search="onAccessorySearch">
          <template slot="option" slot-scope="option">
              <span>{{ option.name }}</span>
              <span>{{ option.sku }}</span>
          </template>
  </v-select>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.