Search code examples
javascripteventssettimeoutaddeventlisteneronkeyup

input onKeyUp Event with timeout


I am trying to create a simple debounce for text input. Following is the code:

<body>
    <input id="myInput" type="text" />
</body>
<script>
    function save(data) {
        console.log('saved!!', myInput.value);
    }

    //function process(e, callback, delay) { signature is changed like this, when we call onKeyUp
    function process(callback, delay) { //signature is changed to this, when we call 'process' directly
        //console.log('e', e, 'callback', callback, 'delay', delay);
        let timer;
        return function () {
            clearTimeout(timer);
            timer = setTimeout(callback, delay);
        }
    }

    function onKeyUp(e) {
        //console.log('onKeyUp')
        process(e, save, 1000)
    }

    //const inp = document.querySelector("#txtInput");
    const inp = document.getElementById("myInput");
    inp.addEventListener(
        'keyup',
        //process(save, 1000) //works
        onKeyUp //-- > does not work
    );
</script>

If I simply call process function on keyup event, it works as expected.

However, I also want to pass e.target.value, and hence I want to event object as well. Hence, to achieve that when I tried calling another function called onKeyUp , which captures event object and when I pass it to process(e, save, 1000) the setTimeout isn't getting called and hence save function isn't getting triggered.

My question is what is the difference when we call process funtion directly on event listener and when we call another function and pass event object to it.


Solution

  • The process(save, 1000) works because it return a function (the anonymous function returned in process()) which passes to inp.addEventListener as the second parameter

    inp.addEventListener(
        'keyup',
        process(save, 1000)
    );
    // equals to 
    const callback = process(save, 1000); //get the anonymous function returned in `process()`
    inp.addEventListener(
        'keyup',
        callback
    ); //callback will be called like callback() when keyup
    

    but when change it to onKeyup, the anonymous function will not be called, so the setTimeout won't work, so does the save function

    inp.addEventListener(
        'keyup',
        onKeyup
    ); // onKeyup will be called like onKeyup() 
    function onKeyUp(e) {
        process(e, save, 1000) // process called
    }
    function process(e, callback, delay) { 
        let timer;
        return function () { // not called, it returns as a function only
            clearTimeout(timer);
            timer = setTimeout(callback, delay);
        }
    }
    

    To fix it. you can do

    function onKeyUp(e) {
        process(e, save, 1000)(); 
    }
    let timer; //assign the `timer` as a global variable
    function process(e, callback, delay) { 
        return function () {
            clearTimeout(timer);
            timer = setTimeout(callback, delay);
        }
    }
    

    More further, you don't need onKeyup if you just want to get the event parameter.In the first code, the anonymous function was called when keyup, it accepted the event parameter already.

    function process(callback, delay) { 
        let timer;
        return function (e) { // you can get `e` here
            clearTimeout(timer);
            timer = setTimeout(callback, delay);
        }
    }