Debounce feature in a presenter

I want to use a debounce feature in a presenter to cut down on the instances of a function being called for user input entry.

So having implemented many versions of the same thing, I end up with the same result - I just cannot get it to delay as expected.

So for example my function is declared (in frontend.js) as

    debounce: function(callback, wait = 500) {

        let timeoutId;

        return (...args) => {

            clearTimeout(timeoutId);

            timeoutId = setTimeout(() => {

            callback.apply(this, args);

            }, wait);

        };

    },

and then in my HTML - im just doing.

<input v-if=“mandatory == ‘0’” class=“col-form-value col-form-value valid_string valid_max_length form-control” :name=“mats.input_name” :id=“mats.input_name” :data-max_length=“255” :maxlength=“255” type=“text” v-model=“value” @keydown=“prevent_submit” @keyup=“debounce(partner_match($event, value, matching_enable, blacklist_enable))” autocomplete=“off”/>

it all works - calls my actual function with the parameters (args) I need …. just with no delay function as would be expected.

Any thoughts ?

Unless vue does something different, the way this is written…

debounce(partner_match($event, value, matching_enable, blacklist_enable))

would mean partner_match is called immediately, and its return value is then sent as a param to debounce.

You could use a reference to function not call it, that should call it only once?!?

Bob,

Yes this may well be what’s happening.

That being said even with some intermediary function being called I still get the result.

    match: function(e, value, mEnabled, bEnabled) {

        this.debounce(this.partner_match(e, value, mEnabled, bEnabled));

    },
        <input v-if="mandatory == '0'" class="col-form-value col-form-value valid_string valid_max_length form-control" :name="mats.input_name" :id="mats.input_name" :data-max_length="255" :maxlength="255" type="text" v-model="value" @keydown="prevent_submit" @keyup="match($event, value, matching_enable, blacklist_enable)" autocomplete="off"/>

There is never any delay and the intended function is getting called with every keyboard press.

to me it looks suspiciously like the timeoutId being used is just not being persisted through the loops and therefore every instance of a keypress is just creating a new timer delay rather than resetting the existing one.

I can now get it to delay but it still calls my method for every keypress which is clearly not what is intended by this function.

This is effectively the same as before, you’re not passing the partner_match function as a param, you’re passing its result. So it has already executed before it gets as far as your timeout id logic.

To delay execution in this way you either need to pass the function name and its params as individual params…

@keyup=“debounce(partner_match, $event, value, matching_enable, blacklist_enable)”

(with the relevant changes to debounce to gather those args), or use an anonymous function…

@keyup=“debounce(function($event, value, matching_enable, blacklist_enable) { //partner_match logic here })”

Thanks for the update Bob.

That also works - although again without the actual delay (timer reset).

My lookup / search function is still called for every single key press.

Calling the function is not the issue (and onward calling my function is also fine).

It feels like there is just no scope (or incorrect scope) to correctly set the timeoutId ….

which is why instead of re-using it - its simply creating a new one during every invocation

Yeah it’s a little confusing to understand the scopes, but my gut feeling is your declaration of timeoutId is probably in the wrong place, it needs to be global. Currently each time you call debounce it’s redeclared within that scope only, it won’t be shared from one call to the next I don’t think.

Any advice on where to put it - if I declare it in a block in the html it didn’t seem to make any immediate difference.

Not sure I can directly declare it globally inside the frontend.js can I ?

I’m not totally sure sorry, my JS skills are rusty so I’d be resorting to trial and error, but it’s worth a try in frontend.js.

OK I’ve finally got there :winking_face_with_tongue:

in my main.htm ive declared (in script tags)

let window.timeoutId;

then in the frontend.js

    debounce: function(callback, wait = 750) {

        return (...args) => {

            clearTimeout(window.timeoutId);

            window.timeoutId = setTimeout(() => { callback.apply(this, args) }, wait);

        };

    },

    match: function(value, mEnabled, bEnabled) {

        this.debounce(this.partner_match)(value, mEnabled, bEnabled);

    },

	partner_match: function(value, mEnabled, bEnabled) {
        ...
    }

and then its just normal eventing in the html to call the functionality.