简体   繁体   中英

How can I make sure a function only runs once with multiple bindings and events firing?

I'm working withjQuery.payment on a credit card number text input field. When the user enters any 4th number (4, 8, 12) the plugin automatically puts in a space for a nice look. Because of this, only the keyup event fires, not the input event. However, if the user were to right-click and paste a value in, then only the input event fires. So we have cases where it's one or the other, or both events firing.

I have a bound anonymous function for change keyup input to ensure all use-cases are covered, but I want the function to only run once each time the key is pressed, but normal key presses fire both keyup and input . jQuery's .one() is not an option because this function needs to run more than once, just not twice for one key press. How can I make sure this function only runs once even when both events are fired from one key press?

I know I could edit jQuery.payment and trigger the input event, but I don't want to modify vendor plug-ins, in case I decide to change versions or something down the road.

You could play around with attaching/detaching event handlers all day and never hit on a successful formula.

If your event handler was idempotent (for a given input state), then you wouldn't need to worry about triggering it twice.

If the handler is not naturally idempotent, then you can include a condition which ensures that a second successive call, with the same input value, does nothing. It's slightly contrived, but this can be regarded as "forced idempotence".

To achieve this, the input element's "last state" (its value) needs to be stored, read back and tested.

You could store the state in some outer/global javascript var but it's neater to use a '.data()' property of the element itself (which is actually 100% js, not pushed into the DOM).

$(function() {
    $("#myInput").on("keyup input", function(e) {
        var $this = $(this),
            $lastState = $this.data('lastState') || '',//read back the element's previous state (or empty string if this is the first call)
            val = $this.val();//current state
        if(val !== $lastState) {//the all-important test.
            $this.data('lastState', val);//store current state to be read back at next call
            //here do whatever is required of your event handler.
        }
    });
});

I would use jQuery change event and always make sure the event was not binded before. And i would not follow a logic like "when user presses the 4th digit". Instead i would format the whole text every time.

function MyInputChanged(){
  var currentText = $("#myInput").val();
  var newText = someFunctionToFormatText(currentText);
  $("#myInput").val(newText);
}

$("#myInput").unbind("change", MyInputChanged);
$("#myInput").bind("change", MyInputChanged);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM