admin管理员组

文章数量:1292173

I have a directive in which I bind focus and click events to element:

app.directive('mydirective', function () {
  return {
    link: function ($scope, $element, $attrs) {
      $element.bind('click focus', function (e) {
        foo(e);
      });
    }
  };
});

I want to call foo once if focus or click event fired. But when clicking on element, focus event gets fired and foo gets called twice. how to prevent calling foo for the second time?

Edit: Yes. I wasn't a good idea to mix hover with click and focus. Thanks every body

I have a directive in which I bind focus and click events to element:

app.directive('mydirective', function () {
  return {
    link: function ($scope, $element, $attrs) {
      $element.bind('click focus', function (e) {
        foo(e);
      });
    }
  };
});

I want to call foo once if focus or click event fired. But when clicking on element, focus event gets fired and foo gets called twice. how to prevent calling foo for the second time?

Edit: Yes. I wasn't a good idea to mix hover with click and focus. Thanks every body

Share edited Jul 24, 2020 at 11:30 Reyraa asked Dec 15, 2014 at 12:03 ReyraaReyraa 4,2943 gold badges30 silver badges57 bronze badges 6
  • 1 why don't you only use focus – Naeem Shaikh Commented Dec 15, 2014 at 12:06
  • @naeem-shaikh this is a kind of tooltip, so element may not be an input. I corrected my question – Reyraa Commented Dec 15, 2014 at 12:08
  • 1 if you are going to bind click along with focus, then your foo function is fired twice, because for clicking on element you need to move your cursor focus to that element, so first focus will fire and then your are clicking that element so again foo is fire with click event, so please choose either click or focus event to bind with. – Tejas Vaishnav Commented Dec 15, 2014 at 12:09
  • 1 You can use .one from jquery or listen to Naeem Shaich because hover is always triggered. You can't ckick without hover – Catalin Lungu Commented Dec 15, 2014 at 12:10
  • Note that you should never bind the hover event. – adeneo Commented Dec 15, 2014 at 12:14
 |  Show 1 more ment

3 Answers 3

Reset to default 6

You can debounce the events, that would only fire the function for the first event

$element.bind('click focus', function(e) {
    if ( !$(this).data('fired') ) foo(e);

    $(this).data('fired', true);

    setTimeout(function(self) {
        $(self).data('fired', false);
    }, 200, this);

});

FIDDLE

One more version of debounce function implementation:

link: function($scope, $element, $attrs) {

    var callOnce = (function() {
        var timeout;
        return function(e, callback) {
            clearTimeout(timeout);
            timeout = setTimeout(function() {
                callback.call(self, e);
            }.bind(this), 200); 
        };
    })();

    $element.bind('click focus mouseover', function(e) {
        callOnce.call(this, e, foo);
    });
}

Demo: http://plnkr.co/edit/HjwedaqUcGj6KncpDtwJ?p=preview

  1. I would suggest using only the focus event if you want the foo() to be called on click and focus both because click will not fire alone but will also cause element to be focused,

  2. as you mentioned that element may not be input, so you can use the click event only instead of focus

  3. but in your case as you say it is fired 3 times, maybe click is fired twice and focus fired once OR focus fired twice and click fired once, in this case use e.preventDefault(); in your click and focus event,

    app.directive('mydirective', function () {
      return {
        link: function ($scope, $element, $attrs) {
          $element.bind('click', function (e) {
            e.preventDefault();
            foo(e);
          });
        }
      };
    });
    

    this way you can make sure same event callback doesn't continue executing twice.

  4. Or the simplest way would be to check if the element is input the bind the focus event otherwise bind the click event

    app.directive('mydirective', function () {
      return {
        link: function ($scope, $element, $attrs) {
    
            if(element is input)
            {    
                  $element.bind('focus', function (e) {
                    e.preventDefault();
                    foo(e);
                  });
            }
            else
            {       
                  $element.bind('click', function (e) {
                    e.preventDefault();
                    foo(e);
                  });
            }
        }
      };
    });
    

本文标签: javascripthow to call foo only if click OR focus firedStack Overflow