Fluffy
Fluffy

Reputation: 28392

jQuery: how to stop propagation to the same handler?

Consider the following code:

$(document).click(function (event) {
  console.log("Ok");
});

$(document).add($('p')).click(function onceHandler(event) {
  console.log('Clicked.');
});

I would like to make the onceHandler run only once when "p" is clicked, so each handler should run once instead of the second one running twice due to the click propagating from p to document.

event.stopPropagation() will break the first handler, so I can't use it. I've also tried:

$(document).add($('p')).click(function(event) {
  if (event.stopDoingThat) return;
  console.log('Clicked.');
  event.stopDoingThat = true;
});

which didn't work. So basically without changing anything I'm getting 2 "clicked" and one "ok". With stopPropagation - 1 "clicked", what I need is 1 "clicked" and 1 "ok"

Upvotes: 1

Views: 385

Answers (5)

karim79
karim79

Reputation: 342755

Does this not do the job? I think you could make things simple with a single event handler and the testing of the target element:

$(document).click(function(event) {
    if(event.target.tagName.toLowerCase() === "p") {
       console.log("clicked");
    }
    console.log("ok");
});

Demo.

Upvotes: 0

Will
Will

Reputation: 481

Have you tried:

var firstRun = true;

$(document).click(function (event) {
  console.log("Ok");
});

$(document).add($('p')).click(function onceHandler(event) {
  if(firstRun) {
    console.log('Clicked.');
    firstRun = false;
  }
});

There is probably a more elegant solution. Something along the lines of:

$(document).click(function (event) {
  console.log("Ok");
});

$(document).add($('p')).on("click.runonce", function(event) {
    console.log('Clicked.');
    $(document).off("click.runonce");
  }
});

Referenced from this other SO question

Upvotes: 1

jorgenfb
jorgenfb

Reputation: 2247

the problem is that you use the apply function on the document-object twice instead of on the paragraph-object. Change your last line so that it look like this:

$(document).click(function (event) {
  console.log("Ok");
});

$(document).add($('p').click(function onceHandler(event) {
    console.log('Clicked.');
    $('p').off('click');
  }
}));

Upvotes: 0

James Montagne
James Montagne

Reputation: 78730

Not sure if this will work in all browsers, but I tested it in chrome.

$(document).click(function (event) {
  console.log("ok");
});

$(document).add($('p')).click(function onceHandler(event) {
    if(!event.originalEvent.myClickDone){
        console.log("click");    
    }

    event.originalEvent.myClickDone = true;
});

Basically, both event objects share a common originalEvent.

Upvotes: 1

Xion
Xion

Reputation: 22780

It seems like a perfect use case for the one function from jQuery:

Description: Attach a handler to an event for the elements. The handler is executed at most once per element.

In your case, this would translate to something like the following code:

$(document).add($('p')).one('click', function onceHandler(event) {
    console.log('Clicked.');
});

More information on is to be found in jQuery docs.

Upvotes: 2

Related Questions