-1

I have a child component that emits a value, and in the parent I perform an axios call with this value each time it is emitted. My problem is that I want to trigger the axios call only if in x ms (or seconds) the child has not emmited another value in order to reduce the amount of calls I do.

Code here :

<script>
import axios from "axios";

import DataTable from './DataTable.vue';

export default {
    name: 'Test',
    data() {
        return {
            gamertags: [],

            // Utils
            timeout: 500,
            delay: 500
        }
    },
    methods: {
        // API calls
        async getGamerTags(string='') {
            const path = `http://localhost:5000/gamertags?string=${string}`
            await axios.get(path)
                .then((res) => {
                    this.gamertags = res.data;
                })
                .catch((error) => {
                    console.error(error);
                });
        },

        // DataTable
        handleFilters(filters) {
            clearTimeout(this.timeout);
            this.timeout = setTimeout(this.getGamerTags(filters.find(o => o.field == "playerGamerTag").filter), this.delay);
        }
    }
    components: {
        DataTable
    }
};
</script>

<template>
    <DataTable
        @filters="handleFilters"
    />
</template>

Thanks in advance.

hitaton
  • 103
  • 2
  • 15
  • 1
    Debouncing is what you are looking for https://lodash.com/docs/4.17.15#debounce. – radovix May 12 '22 at 08:32
  • `setTimeout` expects a function as a first argument. You are not passing a function, you are calling your function and passing it's result into `setTimeout` – Michal Levý May 12 '22 at 09:07

3 Answers3

2

What you need is debouncing. Here is an example:

var timeout, delay = 3000;

function func1() {
  clearTimeout(timeout);
  timeout = setTimeout(function(){
    alert("3000 ms inactivity");
  }, delay);
}
<input type="text" oninput="func1()">

When emitted, simply call func1(), and if there are no new emissions after 3000 ms, the function in timeout will be executed.

Henryc17
  • 851
  • 4
  • 16
  • I added my code, and your solution seems to not work. Like the function is triggering every time a value is emitted, and after 500 ms i have this error ```Uncaught SyntaxError: Unexpected identifier``` – hitaton May 12 '22 at 08:56
  • @hitaton, I've added a snippet into my answer, and it works normally. – Henryc17 May 12 '22 at 09:09
  • @hitaton, furthermore, the syntax error might be caused by a missing or unneeded comma, semicolon or other identifiers in your original code. – Henryc17 May 12 '22 at 09:11
  • So i figured that I should change my code to ```this.timeout = setTimeout(function() {this.getGamerTags(filters.find(o => o.field == "playerGamerTag").filter);}, this.delay);``` but with that I have the error ```TypeError: this.getGamerTags is not a function``` – hitaton May 12 '22 at 09:30
  • Ok my bad, I just did not know how to use setTimeout function with params. I posted an answer to my post. Thank you a lot. – hitaton May 12 '22 at 09:34
1

It would be better to understand the problem and use case if you add the code also. but As I could understand the problem these is two way

  1. if you using inside input and triggering based @changed event you can add @change.lazy this not trigger on each change.
  2. second solution is to use setTimeout(function,delayInMs) inside parent

vuejs Docs link

hackCharms
  • 46
  • 5
  • ```@change.lazy``` is not what I want, I want something like in this post : https://stackoverflow.com/questions/1909441/how-to-delay-the-keyup-handler-until-the-user-stops-typing And i added code in the post – hitaton May 12 '22 at 08:57
0

By simply changing the handleFilters function to :

handleFilters(filters) {
   clearTimeout(this.timeout);
   this.timeout = setTimeout(
      this.getGamerTags,
      this.delay,
      filters.find(o => o.field == "playerGamerTag").filter
   );
},

the problem is solved.

hitaton
  • 103
  • 2
  • 15