0

I'm using jQuery 1.7.2 with Zoomy and jmpress plugins. Also I'm using boilerplate+bootstrap downloaded from initializr.com

I'm trying to create a "game" like [Waldo/Wally] when you have to find some character in a photo. Each photo has a different character to find.

I'm using jmpress as a presentation plugin to go from one photo to another every time the character is found. jmpress loads the content trough ajax (and I need that behavior) because I want a pretty fast load of the web.

Problem: The .on("click") event is not being caught on one of the elements that exist inside the content loaded.

As an example, I'll explain my problem with one of this characters (just taking parts of code).

I have in my index.html some divs to load the characters, I'll take the nurse character:

<div id="nurse" class="step container" data-src="women/nurse.html" data-x="7500">
  Loading...
</div>

The jmpress load the data-src (women/nurse.html) trough ajax when the user is near to that div (step). It loads great.

This is the code of nurse.html

<script type="text/javascript">
    new Image().src = "img/nurse_big.jpg";
</script>
<div class="descripcion">
    <p>Bla, bla, bla.</p>
</div>
<div class="imagen">
    <a href="img/nurse_big.jpg" class="zoom"> <img src="img/nurse.jpg" alt="Find the nurse" /> </a>
</div>

As you can see, I have two divs loaded inside the #nurse div (that has .step class).

I have this code on my js/script.js file when I try to catch the click event:

$(".step").on("click", function(event){
    console.log(event.target);
});

I'm also trying with "body" tag to see what happens

$("body").on("click", function(event){
    console.log(event.target);
});

If you check the console while the message is showing (div.descripcion) it catch the event and print. But, after the div.descripcion is removed and the image appears, it dosen't. Like if that div.imagen or even elements inside it dosen't exist. The click event is not catched. I tried to catch mousemove event and It does.

Why is not catching the click? any idea?

You can see a working version: [Removed]

And the not working version: [Removed]

UPDATE: I forgot, if I use .on("click") it dosen't work. But if I use .on("mousemove") for example, it works. That's the weird part. .on() is working, but not for the click event.

UPDATE 2: I have removed the links of the live examples because they where dev versions. I'll publish the link to the final work when is published. Thanks to all of you for taking the time. Specially to @Esailija that gives me the answer.

Yaazkal
  • 121
  • 1
  • 10
  • possible duplicate of [jQuery - Click event doesn't work on dynamically generated elements](http://stackoverflow.com/questions/6658752/jquery-click-event-doesnt-work-on-dynamically-generated-elements) – Esailija Jun 24 '12 at 19:40
  • ok that one uses live... but there are over 9000 duplicates of this posted daily – Esailija Jun 24 '12 at 19:40
  • Also viewed some "duplicates" on this site, but my problem was not solved and I think that the issue that I wrote is very different. Please see that I'm using .on() event that is the correct. – Yaazkal Jun 24 '12 at 19:49
  • There is plenty of duplicates on `.on` as well..http://stackoverflow.com/q/9484295/995876 – Esailija Jun 24 '12 at 19:54
  • Fyi, the `language` attribute of ` – ThiefMaster Jun 24 '12 at 21:39
  • Thanks @ThiefMaster I'll change that on my code :) – Yaazkal Jun 24 '12 at 21:42

4 Answers4

4

Once again, you need to use on for content loaded later on:

$("body").on("click", ".step", function(event){
    console.log(event.target);
});

Replace body with the closest static element that holds the .step elements.
Static means exist in the DOM when the you execute the line:

$(...).on("click", ".step", function(event){

Example:

$('#ContainerId').on("click", ".step", function(event){
    // Do what you want.
});

Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers

on docs

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • 2
    Dang it. Beat me to it. :-p I was typing the answer when I saw you posted. (+1) – JasCav Jun 24 '12 at 19:38
  • To expand gdoron's answer a little bit, when you use on, in order to implement a 'live' type capability (but it's better than live, don't use live), your selector selects the item, but you wire the action to elements that are going to appear later. In your case, you are selecting the body, and wiring the "click" action to ".step" items that will show up now or in the future. – JasCav Jun 24 '12 at 19:40
  • I can't find your post on meta on not answering duplicates ;D – Esailija Jun 24 '12 at 19:42
  • @Esailija. Mine? I don't have such an answer... Anyway, if you can beat them... Those questions come back all the times, so don't even try to stop it. – gdoron Jun 24 '12 at 19:44
  • @Esailija. I think the way to fight with those repeated questions is to make a good primary thread. This is why I did for the [`$('#id')` questions](http://stackoverflow.com/questions/11114622/). I think this is the only way, once you did that than you can close as duplicate in the minute those question pops. I think to do that for other questions soon. What do you think? – gdoron Jun 24 '12 at 19:49
  • @gdoron sounds great, there are several topics on javascript that have the same answer (`async`, `this`, `floating points`, `delegation` etc.) but popup 150x times per day – Esailija Jun 24 '12 at 19:50
  • @Esailija. I think to start with unique `id` in HTML and javascript, no jQuery involved, as [Felix commented](http://stackoverflow.com/questions/11114622/jquery-id-selector-works-only-for-the-first-element#comment14562037_11114634). I think it's the most repeated question ever. Do you think those questions should be Wiki? – gdoron Jun 24 '12 at 19:55
  • Hello, thanks for taking the time to answer. As I explain in the post, I'm already using .on() event. I understand it. Please see that the event is working on the div.descripcion that is a dynamic element added. But is not working in the div.imagen element that is also a dynamic content loaded in the same div.step That's why I'm posting this and what I don't think is a "duplicate" :) – Yaazkal Jun 24 '12 at 19:55
  • I forgot, if I use .on("click") it dosen't work. But I use .on("mousemove") for example, it works. That's the weird part. .on() is working, but not for the click event. – Yaazkal Jun 24 '12 at 20:13
2

The zoomy plugin you are using does this:

 'click': function () {
    return false;
}

Since the element you are clicking when you are on the image, is actually the zoomy elements, those get to handle the events first. They handle it by returning false, which means doinge.stopPropagation() as well as e.preventDefault(). So the event won't even come to .imagen.

There is also unterminated multi-line comment in your code, not sure what that does but it can't be good. Consider just deleting code instead of commenting it out.

Anyway, clearing everything like this:

$.cache = {}; //Can also do $("*").off() I think

And then doing:

$(".step").on("click", ".imagen", function(event){
    console.log(event.target);
    event.preventDefault();
});

And it works fine. You might wanna edit the plugin to do this instead:

'click': function (e) {
    e.preventDefault();
}

Alternatively you could look for a plugin that is developed by someone who knows what the hell they are doing or write it yourself.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • Thanks !!! Changing the 'click' code on that plugin solves the problem. I'm still using that plugin, I don't know an alternative. By now I'll write to the programmer. Thanks a lot for your time and knowledge :) – Yaazkal Jun 24 '12 at 20:34
  • @Yaazkal please give him my regards :D – Esailija Jun 24 '12 at 20:35
  • @JacobLowe the documented "solution" didn't work for him so why the downvote? :X – Esailija Jun 24 '12 at 21:28
  • @gdoron because the creator of the plugin (Jacob Lowe) is hating :D – Esailija Jun 24 '12 at 21:32
  • @JacobLowe. _"documentation is overated"_ what do you mean by that? – gdoron Jun 24 '12 at 21:34
  • @JacobLowe, Ohhh looked at your profile details, you really are the author of the plugin... I think you should upvote someone finding a bug in your product rather downvoting him. That's how I see those kind of things. Ignoring bugs doesn't look too professional to me. (My answer is below if you want to downvote... `;-)`) – gdoron Jun 24 '12 at 21:53
  • Yep, even if the OP can work around this, the plugin shouldn't break its encapsulation and mess with the outside world in any case. – Esailija Jun 24 '12 at 21:57
  • the plugin can be used as is not modified, and do what is needed. I dont see this as an issue, but im open to reconsidering. If you care to make a pull request https://github.com/jacoblwe20/zoomy-plugin – Jacob Lowe Jun 24 '12 at 22:11
  • I found solution of @Esailija to work. Also, the solution of @ JacobLowe works (Is just that I had to erase the href attribute and tell the plugin to use another). Maybe the documentantion was not clear for me at the time I read it (maybe a visible warning message can prevent confusion) or maybe I'm not cleaver enough to understand it. Now, both solutions work. This is now a thecnical disscution about editing, not edition, bug or not bug. If it's better to use preventDefault() or return false. I'm not able to take judjment on this. Just wanted to thank both of you for your time :) – Yaazkal Jun 24 '12 at 22:22
  • @JacobLowe I have made a pull request – Esailija Jun 24 '12 at 22:26
  • @gdoron looks great, I'll look into it more tomorrow – Esailija Jun 24 '12 at 23:19
0

In the documentation in http://zoomy.me/Options.html you can allow the plugin to have a clickable area by adding in true to the clickable option.

So when calling zoomy() on a element all you have to do is add a little bit of code inside the zoomy function.

$('.element').zoomy({clickable:true});

and that should fix everything,

Jacob Lowe
  • 698
  • 7
  • 16
  • I also tried this, but when I clicked, it opens the large image and I don't wanted that. – Yaazkal Jun 24 '12 at 21:13
  • then you need to do the `e.preventDefault()` or `return false` within your own code when you are calling your click event. – Jacob Lowe Jun 24 '12 at 21:29
  • I confirm that untouching the plugin, and using clickable:true works but If I change the attr to not use href. Now, I'm confused. What should I use? Edit the script or use the clickable feature? I thing this is now a technical discussing about what is wrong/right. Thanks to all – Yaazkal Jun 24 '12 at 21:32
  • @Yaazkal if you don't need the href then that's probably cleaner than editing the insides of the plugin. – Esailija Jun 24 '12 at 21:36
  • meaning you can use a different attribute you can use something like data-image eg. ` – Jacob Lowe Jun 24 '12 at 21:48
0

The alternative way to catch the function on click event is just like below.

    <div onclick="fireClickEvent();" > Just firing the click event!</div>

    function fireClickEvent() {
        console.log(event.target);
    }
Atif Hussain
  • 880
  • 12
  • 19