I have a simple input box in a Vue template and I would like to use debounce more or less like this:
In case you need to apply a dynamic delay with the lodash's debounce
function:
props: {
delay: String
},
data: () => ({
search: null
}),
created () {
this.valueChanged = debounce(function (event) {
// Here you have access to `this`
this.makeAPIrequest(event.target.value)
}.bind(this), this.delay)
},
methods: {
makeAPIrequest (newVal) {
// ...
}
}
And the template:
<template>
//...
<input type="text" v-model="search" @input="valueChanged" />
//...
</template>
NOTE: in the example above I made an example of search input which can call the API with a custom delay which is provided in props
If you could move the execution of the debounce function into some class method you could use a decorator from the utils-decorators lib (npm install --save utils-decorators
):
import {debounce} from 'utils-decorators';
class SomeService {
@debounce(500)
getData(params) {
}
}
Very simple without lodash
handleScroll: function() {
if (this.timeout)
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
// your action
}, 200); // delay
}
updated in 2020
(Recommended if needed more than once in your project)
helpers.js
export function debounce (fn, delay) {
var timeoutID = null
return function () {
clearTimeout(timeoutID)
var args = arguments
var that = this
timeoutID = setTimeout(function () {
fn.apply(that, args)
}, delay)
}
}
Component.vue
<script>
import {debounce} from './helpers'
export default {
data () {
return {
input: '',
debouncedInput: ''
}
},
watch: {
input: debounce(function (newVal) {
this.debouncedInput = newVal
}, 500)
}
}
</script>
Codepen
(Recommended if using once or in small project)
Component.vue
<template>
<input type="text" v-model="input" />
</template>
<script>
export default {
data: {
debouncedInput: ''
},
computed: {
input: {
get() {
return this.debouncedInput
},
set(val) {
if (this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
this.debouncedInput = val
}, 300)
}
}
}
}
</script>
Codepen
If you are using Vue you can also use v.model.lazy
instead of debounce
but remember v.model.lazy
will not always work as Vue limits it for custom components.
For custom components you should use :value
along with @change.native
<b-input :value="data" @change.native="data = $event.target.value" ></b-input>
Please note that I posted this answer before the accepted answer. It's not correct. It's just a step forward from the solution in the question. I have edited the accepted question to show both the author's implementation and the final implementation I had used.
Based on comments and the linked migration document, I've made a few changes to the code:
In template:
<input type="text" v-on:input="debounceInput" v-model="searchInput">
In script:
watch: {
searchInput: function () {
this.debounceInput();
}
},
And the method that sets the filter key stays the same:
methods: {
debounceInput: _.debounce(function () {
this.filterKey = this.searchInput;
}, 500)
}
This looks like there is one less call (just the v-model
, and not the v-on:input
).