LimitW
LimitW

Reputation: 43

Click event function executes twice

I'm puzzled about the result of this code. In my opinion, when the content of $("#title") is "hello" and get a click, it executes function saygoodbye() and add a new click-event anonymous function. It gets an outer alert. When the content is "goodbye" and get a click, both of these two functions should execute. It should get one outer alert and ONE inner alert.

But in fact, I get one outer alert and TWO inner alerts. Where is the other inner alert from?

var count = 0;
function saygoodbye(){
  alert("ok is outer");
  $("#title").html("goodbye");
  $("#title").click(function() {
    alert("ok is inner");
    $('#title').html("hello");
    $('#title').off("click");
  });
}
<script src="//code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script>

<h1 id="title" onclick="saygoodbye();">hello</h1>

Upvotes: 3

Views: 445

Answers (2)

JayKandari
JayKandari

Reputation: 1248

That is because the event is getting registered from DOM. Register it dynamically, Then It works.

Remove onclick attribute from markup.

var count = 0;

$('#title').click(saygoodbye);

function saygoodbye(){
  alert("ok is outer");
  $("#title").html("goodbye");
  $("#title").click(function() {
    alert("ok is inner");
    $('#title').html("hello");
    $('#title').off("click");
  });
}
<script src="//code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script>
<h1 id="title">hello</h1>

Read this SO thread to get an insight as to why to register events on the go (For your case). jQuery.click() vs onClick

EDIT:

First, In order to unbind events which are triggered thru element's attribute we need to use

document.getElementById("title").onclick = null;

Secondly, jQuery's .off() function will only unbind handlers that were added by jQuery's .on()

Documentation at http://api.jquery.com/off/

  • "The .off() method removes event handlers that were attached with .on()"
  • .click() - is a shorthand methods of .on()

So saygoodbye() doesn't get away, Here is the debugging.

click title.(having title hello)

  1. call goodbyefunction alert 'outer';
  2. change html to 'goodbye' assign
  3. new anonymous handler to title (on click event).

click title (having title goodbye)

  1. call goodbyefunction
  2. alert 'outer';
  3. change html to 'goodbye' (yes it changes again)
  4. assign another event anonymous handler to title (see 1 more handler attached)
  5. call anonymous handler 1
  6. alert 'inner'
  7. although at this stage (.off() function is specified. this will only execute if all events are triggered);
  8. call anonymous handler 2
  9. alert 'inner '
  10. .off() function works here and kills extra added 2 handlers.

Hope this breakdown helps.

Upvotes: 2

Pointy
Pointy

Reputation: 413717

  1. The first time you click, "saygoodbye" runs, posts the "outer" alert, and establishes a click handler.
  2. The second time you click, "saygoodbye" runs again, posts "outer", and establishes yet another click hander.
  3. That "click" event is then handled by jQuery, which at this point has two of your "click" handlers to call.

When you call .click(), you're always adding a new handler; previously added handlers are not removed. They'll be removed when you call .off(), but that doesn't happen until two handlers have already been attached. The library (jQuery that is) maintains lists of handlers and uses it's own internal event handler to actually handle the event from the browser. Thus even though there are only two real "click" events, by the time the jQuery handler is invoked there are two jQuery-registered handlers for the library to call.

In general, adding event handlers inside other event handlers is a questionable way of doing things. It's not exactly wrong, but it adds complexity. Here, on top of that, you're using two separate techniques to register event handlers. The "saygoodbye" function is attached to the DOM element's "onclick" property. The jQuery code, however, uses the DOM API attachEventHandler() to register handlers. Those two mechanisms are separate. When a "click" happens, the browser will check the "onclick" property first and then call any handlers registered via the API.

Upvotes: 5

Related Questions