Home > Mobile >  VueJS: 'once' event modifier, check if clicked
VueJS: 'once' event modifier, check if clicked

Time:03-30

I have a simple question to which I have not answer so far.

In VueJS there is the .once event modifier which works fine. The thing is that I use a @click.once on an autocomplete input component to query my database and populate its available items.

The thing I want to achieve is to provide some sort of appended icon to call the query after that the input has been clicked once.

The reasons are :

  • I want to prevent the user to spam click on the input and make tons of queries
  • I want him to be able to refresh the data with a "refresh icon" which would be displayed only if my input has been clicked once (@click.once triggered).

Is there a way to get this info ?

Thanks in advance !

CodePudding user response:

I think you're on the wrong track here. Acting based on the event being removed is not easy as you would need to dig deep into Vue's virtualization (this._vnode.children) to extract this information. This is highly discouraged.

Best practice in that case would be to keep track of the states in your system yourself by introducing and updating your own variables/attributes and building the mechanisms based on those values. Technically, this can omit the initial use of .once altogether.

So, you need at least one variable for keeping track if the data is already loaded (loadedDataOnce in my example below).
At this point a small note: It makes just in general more sense to setup this stuff based on the state of the content being loaded and/or loading and not the interface and their event states. ;)

Another variable could help to block the user from button spamming during the loading of the API (loadingData).

Here's a hastily coded example on how this could look like in practice:

var app = new Vue({
  el: '#app',
  data: {
  
    // variables to track current state of the data requests:
    loadingData: false, // true when currently pulling data
    loadedDataOnce: false, // true when data was pulled at least once before
    
    // variable for the data which is displayed on the page
    displaydata: ['...no data to display yet']
    
  },
  methods: {
    // event handler with dummy API request
    async pullData() {
      // block clicking while loading data
      this.loadingData = true;
      // simulate API request time
      await new Promise(r => setTimeout(r, 2000));
      this.displaydata = ['Apples', 'Bananas', 'Cherries', 'Dragon Fruits', 'Eggfruits', 'Figs', 'Grapes']
         .sort(()=>Math.random()-0.5);
      // keep in mind that the data was loaded at least once and the refresh button thas to be showen
      this.loadedDataOnce = true;
      // allow clicking the buttons again
      this.loadingData = false;
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
  <button v-if="!loadedDataOnce" @click="pullData" :disabled="loadingData">load data</button>
  <button v-else @click="pullData" :disabled="loadingData">⟳ refresh data</button>
  
  <br><br>
  <ul>
    <li v-for="entry of displaydata">{{entry}}</li>
  </ul>
</div>

CodePudding user response:

I think you should create a state (data) that is set to false, and when the button is clicked it changes to false. Then conditionally display the refresh icon with the set value. On click of the refresh reset value to false.

<template>
    <div>
      <button @click.once="makeQuery">Make Query</button>
      <button v-if="makeQueryClicked" @click="refresh">Refresh</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            makeQueryClicked: false
        }
    },
    methods: {
        makeQuery() {
             this.makeQueryClicked = true
        },
        refresh() {
             this.makeQueryClicked = false
             //add the action you want to happen when you refresh
        }
    }
}
</script>
  • Related