How to run a function once when binding to multiple events that all trigger in Javascript?

前端 未结 5 1076
失恋的感觉
失恋的感觉 2020-12-19 20:23

I have a search input that listens to keyup and change to trigger an update of a listview via Ajax.

Looks like this:

input.on         


        
相关标签:
5条回答
  • 2020-12-19 20:30

    I would try to set up a value-checking function like this:

    var $inputIntance = $("#path-to-your-input");
    var lastInputValue;
    
    function checkInputValue () {
        var newValue = $inputIntance.val();
        if (newValue != lastInputValue) {
            // make your AJAX call here
            lastInputValue = newValue;
            el = $inputIntance.closest('ul');
            widget[func](dyn, el, lib_template, locale, lastInputValue, "update");
        }
    }
    

    and then then fire this checks by any user-action event you like:

    $inputIntance.on('keyup change', function(e) {
        checkInputValue();
    }
    

    or like this

    $inputIntance.on('keyup change', checkInputValue );
    

    UPDATE: there might be the case when you have to limit the number of AJAX requests per time. I added time control functionality to my previous code. You can find the code below and try it live here in JSFiddle.

    $(document).ready(function () {
        var $inputIntance = $("#test-input");
        var lastInputValue;
        var valueCheckTimer;
        var MIN_TIME_BETWEEN_REQUESTS = 100; //100ms
        var lastCheckWasAt = 0;
    
        function checkInputValue () {
            lastCheckWasAt = getTimeStamp();
            var newValue = $inputIntance.val();
            if (newValue != lastInputValue) {
                // make your AJAX call here
                lastInputValue = newValue;
                $("#output").append("<p>AJAX request on " + getTimeStamp() + "</p>");
                //el = $inputIntance.closest('ul');
                //widget[func](dyn, el, lib_template, locale, lastInputValue, "update");
            }
        }
    
        function getTimeStamp () {
            return (new Date()).getTime();
        }
    
        function checkInputValueScheduled() {
            if (valueCheckTimer) { // check is already planned: it will be performed in MIN_TIME_BETWEEN_REQUESTS
                return;
            } else { // no checks planned
                if  ((getTimeStamp() - lastCheckWasAt) > MIN_TIME_BETWEEN_REQUESTS) { // check was more than MIN_TIME_BETWEEN_REQUESTS ago
                    checkInputValue();
                } else { // check was not so much time ago - schedule new check in MIN_TIME_BETWEEN_REQUESTS
                    valueCheckTimer = window.setTimeout(
                        function () {
                            valueCheckTimer = null;
                            checkInputValue();
                        }, 
                        MIN_TIME_BETWEEN_REQUESTS
                    );
                }
            }
        }
    
        $inputIntance.bind('keyup change', function(e) {
            $("#output").append("<p>input event captured</p>");
            checkInputValueScheduled();
        });
    });
    
    0 讨论(0)
  • 2020-12-19 20:35

    Any reason for listening to keyUp in addition to change? Maybe what really matters is just one of these events.

    If not, I guess you will have to use a closure as you suggested.

    0 讨论(0)
  • 2020-12-19 20:39

    If one is triggered first, then delete the other.

    const handler = e => {
      const eventType = e.type === 'mousedown' ? 'click' : 'mousedown';
      window.removeEventListener(eventType, handler);
    };
    
    window.addEventListener('click', handler);
    window.addEventListener('mousedown', handler);
    
    0 讨论(0)
  • 2020-12-19 20:47

    I came across this problem before and what I ended up doing is saving the request on an object upon creation and test for a previously set one to abort it if necessary. You'd have to edit the function that triggers the ajax call. For example:

    if ( ajaxRequest ) { 
      ajaxRequest.abort();
    }
    ajaxRequest = $.ajax({ ... }); // triggers ajax request and saves it
    

    If the widget function returns an ajax object then you can probably assign that to the variable instead of modifying the original ajax request.

    0 讨论(0)
  • 2020-12-19 20:50

    Ok. I got it (after a felt 1000 tries...).

    Here is what works = triggers whichever event fires first, blocks the trailer:

    var isEven;
    input.on('keyup change', function(e) {
        isEven = true;
        if (timer) {
            window.clearTimeout(timer);
        }
        timer = window.setTimeout( function() {
            timer = null;
            val = input.val();
            el = input.closest('ul');
            // prevent double firing after interval passed
            if (isEven === true ){
                isEven = false;
            } else {
                isEven = true;
                return;
            }
            widget[func](dyn, el, lib_template, locale, val, "update");
        }, interval );
    });
    

    Seems to do what it should. Feel free to correct me, if it's wrong.

    0 讨论(0)
提交回复
热议问题