Max Lynn
Max Lynn

Reputation: 1778

Angular.JS - Event is being triggered multiple times

Code:

scope.offCanvasShow = function ($event) {
  $('.app-off-canvas-menu').toggleClass('show');
  // Prevents default functionality of a element
  // In this instance, this prevents the anchor from reloading the page on click.
  $event.preventDefault();
  $event.stopPropagation();

  $(document).one('touchstart click', offCanvasHandler);

  /**
    * Checks to see if the event target isn't .off-canvas-menu or has off-canvas-menu as a parent then removes the
    * show class.
    * @param event - is the event of the function
   */
  function offCanvasHandler(event) {
    console.log('hello');
    if (!$(event.target).closest('.app-off-canvas-menu').length) {
      $('.app-off-canvas-menu').removeClass('show');
      $(document).off('touchstart click', offCanvasHandler);
  } else {
    $(document).one('touchstart click', offCanvasHandler);
  }
  }
};

This is a simple off canvas drop down menu. I have this odd problem of bubbling. That I thought I fixed with the .one() function.

If you click on the class app-off-canvas-menu a few times and then leave the menu open and click outside of the menu the menu closes which is what I want.

Here is the but, once I clicked outside of the menu it seems that the console log gets run multiple times depending on how many times I've clicked the app-off-canvas-menu hamburger.

Can anyone see anything clearly obvious with my code?

Its worth noting that I am using angular so it might be possible I have to go about this in a different fashion.

Upvotes: 2

Views: 405

Answers (1)

Martijn Welker
Martijn Welker

Reputation: 5605

If you click on the class app-off-canvas-menu a few times and then leave the menu open and click outside of the menu the menu closes which is what I want.

Every time you click on the class you will bind another handler:

$(document).one('touchstart click', offCanvasHandler);

so when you click outside the element it will execute all those handlers.

From the jQuery website:

The .one() method is identical to .on(), except that the handler is unbound after its first invocation.

So you don't bind it once, it only runs once. This might have caused the confusion.


Update with code:

var isBound = false;
scope.offCanvasShow = function ($event) {
  $('.app-off-canvas-menu').toggleClass('show');
    // Prevents default functionality of a element
    // In this instance, this prevents the anchor from reloading the page on click.
    $event.preventDefault();
    $event.stopPropagation();

    if(!isBound) {
      $(document).one('touchstart click', offCanvasHandler);
      isBound = true;
    }

    /**
      * Checks to see if the event target isn't .off-canvas-menu or has off-canvas-menu as a parent then removes the
      * show class.
      * @param event - is the event of the function
     */
    function offCanvasHandler(event) {
      console.log('hello');
      if (!$(event.target).closest('.app-off-canvas-menu').length) {
        $('.app-off-canvas-menu').removeClass('show');
        $(document).off('touchstart click', offCanvasHandler);
    } else {
      $(document).one('touchstart click', offCanvasHandler);
    }
  }
};

Upvotes: 2

Related Questions