Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run a function only once when it's triggered by both focus and click events

I have an input element with 2 events attached: focus and click. They both fire off the same helper function.

When I tab to the input, the focus event fires and my helper is run once. No problems there.

When the element already has focus, and I click on it again, the click event fires and my helper runs once. No problems there either.

But when the element does not have focus, and I click on it, BOTH events fire, and my helper is run TWICE. How can I keep this helper only running once?

I saw a couple similar questions on here, but didn't really follow their answers. I also discovered the .live jQuery handler, which seems like it could work if I had it watch a status class. But seems like there should be a simpler way. The .one handler would work, except I need this to work more than once.

Thanks for any help!

like image 852
dylanized Avatar asked Jan 25 '14 18:01

dylanized


People also ask

How do I run an event only once?

We can pass an object as an argument to the addEventListener method and specify that the event is only handled once. This is achieved by passing the property once to the object. If we set once to true, the event will only be fired once.

How do you attach a event to element which should be executed only once?

Syntax: $(". event-handler-btn"). one("click", function (e) { // Code to be executed once });

What event is triggered when a button element loses focus?

The focusout event fires when an element has lost focus, after the blur event. The two events differ in that focusout bubbles, while blur does not. The opposite of focusout is the focusin event, which fires when the element has received focus. The focusout event is not cancelable.

What is the correct way to trigger a click event?

The HTMLElement. click() method simulates a mouse click on an element. When click() is used with supported elements (such as an <input> ), it fires the element's click event.


2 Answers

You could use a timeout which get's cleared and set. This would introduce a slight delay but ensures only the last event is triggered.

$(function() {
  $('#field').on('click focus', function() {
    debounce(function() {
        // Your code goes here.
        console.log('event');
    });
  });  
});

var debounceTimeout;

function debounce(callback) {
  clearTimeout(debounceTimeout);
  debounceTimeout = setTimeout(callback, 500);
}

Here's the fiddle http://jsfiddle.net/APEdu/

UPDATE

To address a comment elsewhere about use of a global, you could make the doubleBounceTimeout a collection of timeouts with a key passed in the event handler. Or you could pass the same timeout to any methods handling the same event. This way you could use the same method to handle this for any number of inputs.

like image 193
crad Avatar answered Sep 21 '22 14:09

crad


The best answer here would be to come up with a design that isn't trying to trigger the same action on two different events that can both occur on the same user action, but since you haven't really explained the overall problem you're coding, we can't really help you with that approach.

One approach is to keep a single event from triggering the same thing twice is to "debounce" the function call and only call the function from a given element if it hasn't been called very recently (e.g. probably from the same user event). You can do this by recording the time of the last firing for this element and only call the function if the time has been longer than some value.

Here's one way you could do that:

function debounceMyFunction() {
    var now = new Date().getTime();
    var prevTime = $(this).data("prevActionTime");
    $(this).data("prevActionTime", now);
    // only call my function if we haven't just called it (within the last second)
    if (!prevTime || now - prevTime > 1000) {
        callMyFunction();
    }
}

$(elem).focus(debounceMyFunction).click(debounceMyFunction);
like image 30
jfriend00 Avatar answered Sep 20 '22 14:09

jfriend00