Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

phegman's avatar

Debounce from global mixin for live search

I am a bit stuck and wondering if anybody can give me some guidance on how to correctly implement debouncing. First off I have a helpers.js file that looks like this:

const helpers = {
    methods: {
        /**
         * Returns a function, that, as long as it continues to be invoked, will not
         * be triggered. The function will be called after it stops being called for
         * N milliseconds. If `immediate` is passed, trigger the function on the
         * leading edge, instead of the trailing.
         * @param {function} func 
         * @param {Number} wait 
         * @param {String} immediate
         * @return {void}
         */
        debounce(func, wait, immediate) {
            var timeout;
            return function() {
                var context = this, args = arguments;
                var later = function() {
                    timeout = null;
                    if (!immediate) func.apply(context, args);
                };
                var callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if (callNow) func.apply(context, args);
            };
        }
    }
}

export { helpers as default }

Then in my main js file I import it and create a global mixin like so:

/**
 * Mixins
 */
import helpers from './mixins/helpers.js';

Vue.mixin(helpers);

Finally I have a component that looks like this:

<template>
    <div class="form-group">
        <label for="searchAthletes">Search</label>
        <input v-model="athleteSearchString" @keyup="search" type="text" name="searchAthletes">
    </div><!-- /.form-group -->
</template>

<script>
    import { mapGetters } from 'vuex';

    export default {
        props: {
            gender: {
                type: String,
                required: true
            }
        },
        computed: {
            ...mapGetters([
                'loadedAthletes'
            ]),
            athleteSearchString: {
                get() {
                    return this.$store.getters.athleteSearchString;
                },
                set(value) {
                    this.$store.commit('setAthleteSearchString', value);
                }
            }
        },
        methods: {
            /**
             * Search for athletes
             * @return {void}
             */
            search: this.debounce(function() {
                axios.post(route('athlete.search'), {
                    searchString: this.athleteSearchString,
                    gender: this.gender
                }).then((response) => {
                    if (this.athleteSearchString == '') {
                        this.$store.commit('setAthletes', this.loadedAthletes);
                    } else {
                        this.$store.commit('setAthletes', response.data);
                    }
                }).catch((error) => {

                });
            })
        }
    }
</script>

The issue I am running into is I get this error this.debounce is not a function. Any ideas on how to implement this correctly? I could pull in lodash, but as of now I really only need the debounce function so it seems like overkill.

Thanks in advance!

0 likes
4 replies
spodlogar's avatar

I would recommend using Lodash for debouncing.

it makes it as easy as:

    // ADD THIS
    import _ from 'lodash';


    import { mapGetters } from 'vuex';

    export default {
        props: {
            gender: {
                type: String,
                required: true
            }
        },
        computed: {
            ...mapGetters([
                'loadedAthletes'
            ]),
            athleteSearchString: {
                get() {
                    return this.$store.getters.athleteSearchString;
                },
                set(value) {
                    this.$store.commit('setAthleteSearchString', value);
                }
            }
        },
        methods: {
            /**
             * Search for athletes
             * @return {void}
             */
        
            // UPDATE THIS
            search: _.debounce(function() {
                axios.post(route('athlete.search'), {
                    searchString: this.athleteSearchString,
                    gender: this.gender
                }).then((response) => {
                    if (this.athleteSearchString == '') {
                        this.$store.commit('setAthletes', this.loadedAthletes);
                    } else {
                        this.$store.commit('setAthletes', response.data);
                    }
                }).catch((error) => {

                });
            }, 200)
            // ^ ADD THE TIMEOUT
        }
    }
phegman's avatar

Cheers! I suppose lodash is pretty small in general so I will probably just end up pulling it in. Thanks for the help!

nateritter's avatar

Been running into this similar type of problem with Laravel Spark 7.0.2. It uses lodash, but the _.debounce method is never fired.

Example:

Vue.component('accounts-index', {
    props: ['user'],

    data () {
        return {
            accounts: [],
            working: false,
            fetching: false,
            fetchingArchived: false,
        };
    },

    methods: {

// ....

        updateAccount(account) {
            _.debounce(() => {
                  console.log('I only get fired once every 0.5 seconds, max!')
            }, 500);
            account.isSaving = true;
            axios.put(`/api/accounts/${account.id}`, account)
                .then(response => {
                    account.isTracking = this.isTracking(account);
                    account.isSaving = false;
                });
        },

// ...

});

The problem is the console.log is never fired, although everything else works perfectly. Considering lodash is already a part of Spark, I would have assumed this would have worked fine. I've tried importing debounce and _ but to no avail. I do use lodash functions all over the codebase elsewhere and in this file, _.debounce simply will not work and no JS errors are fired to help.

Any additional thoughts?

Please or to participate in this conversation.