As to why the first works until after the first click, if the code in the function you're setting as the click handler replaces the DOM elements you originally bound the click to (the images jQuery found when you ran $('img').on(...
), then the elements you bound the click to are gone and new ones have been put into the DOM. So you originally run the code, and the click is bound and works. But then you click, and cause the replacement of the elements which had click handlers, so no further clicking will work.
The latter works because you're delegating the click handling to the parent container, which container you are not replacing. You see, jQuery's .on
method can be called a number of ways, changing what it binds to and what elements it will react to.
When called as you have, with three parameters, it says that whenever an element in the collection receives a click event from something which matches the selector in the second parameter, the function given in the third parameter will run. Given your second (and working) example:
$("#ocean").on("click", "td img", function()
This says that when the element with ID of ocean
receives a click event, it should check to see if it originated from an image which is in a table cell.
To explain a little more clearly, event bubbling in jQuery happens when any DOM event takes place. If I click an image, any handlers for that image are run, then the event is passed up to the image's parent. Again, any bound handlers are run, and it's passed up again. This continues all the way up to DOM to the document element. (Natively, some browsers don't do this quite the same, but jQuery levels the playing field)
In the example I copied, you're telling jQuery to listen for click events which started at, or have bubbled up to, the DIV with ID ocean
. When it receives such an event, it is to check that the event originated at an image element which lives within a TD. If it does, your function runs.
Even if your function replaces the contents inside of the DIV with ID of ocean
, the delegated click remains bound to ocean
, so bubbled events continue to be caught and handled.
Now, let's go back to your "working once" example--it has some oddities besides the problem you're noticing:
$("img").on("click", "td img", function().....
This says jQuery should listen for events originating at, or bubbling up to, an image element that's in a table cell. Do you see the problem with this? Images cannot have descendent elements, so such a delegation doesn't make a lot of sense.
What this will do is is bind a click to all img
elements in the DOM. When clicked, the event first arrives at the clicked element, an image, and the check for td img
is run. If it matches (if the clicked image was, in fact, inside of a table cell), the handler runs. If images could have descendants, this would also work for any images which live under the clicked image and inside of a TD. This cannot happen, though. So in practice, your code will only bind to images, and run the handler for those which live in a TD. This is identical to:
$("td img").on("click" function().....
This line is better to run as
- It only finds and binds to images which live in a TD
- No further selector matching has to be done to figure out if the handler should run.
Note, though, that this would still suffer the problem of working once, then stopping, if you replace the images you bound the click to. Thus your delegation to ocean
(your second line of code in the original post) is what you need.