I have two lists. I am making it so when you click the first list (instrument), you get a class list based on that instrument.
The first list is pretty clickable and everything seems to be working. But when I click the second list (li) element nothing happens. It seems so far that I can do anything with the second list except for targeting on click i have tried add class and it works but on click doesn't work.
Here's a sample.
The left list onclick works fine but the right one doesn't
Here is a link to the codepen
Link to the Code Pen
Here is the specific code that targets my li element with the class "classList"
$(".classList").on('click',function(){
$(".classList").removeClass("clicked");
$(this).addClass("clicked");
$(".studentInformationView").show();
$("#nameInput").show();
});
The code is too long to put a snippet here so please access the codepen.
Please let me know what's wrong.
Since you are adding your .classList dynamically after the page load you will after to attach your click event differently, as a delegated event.
You can read about jQuery .on() delegated events here.
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time.
Like this:
$(document).on('click', '.classList', function(){
$(".classList").removeClass("clicked");
$(this).addClass("clicked");
$(".studentInformationView").show();
$("#nameInput").show();
});
So attach the event to the document (which will always exist on page load when you are attaching the event), and it will delegate it to the .classList when it gets added at a later time.
Here is an updated CodePen
Related
I'm trying to make a simple tree-view script, and start with opening/closing nodes. But I stuck with some problem:
$(function() {
$('#tree li.closedNode').on('click',function(e){
e.stopPropagation();
$(this).removeClass('closedNode').addClass('openedNode').children(':not(a.caption)').show();
})
$('#tree li.openedNode').on('click',function(e){
e.stopPropagation();
$(this).addClass('closedNode').removeClass('openedNode').children(':not(a.caption)').hide();
})
jsfiddle: http://jsfiddle.net/F33dS/14/
So, then you click on 'click here' it's closing, changing class, but it still firing event for 'li.openedNode'. I know, that I missed somthing simple, but what? I really can't find the problem. So, why it's working in this way?
You're binding event to things that don't exist yet.
You need to use .on() such that it targets all matching elements whether they exist now or in the future.
http://jsfiddle.net/F33dS/16/
$('#tree').on('click', 'li.closedNode', function(e){
e.stopPropagation();
$(this).removeClass('closedNode').addClass('openedNode').children(':not(a.caption)').show();
})
$('#tree').on('click', 'li.openedNode', function(e){
e.stopPropagation();
$(this).addClass('closedNode').removeClass('openedNode').children(':not(a.caption)').hide();
})
Your nodes have the class openNode on page load.
The script looks for $('#tree li.openNode') and matches elements.
The script looks for $('#tree li.closedNode') and matches none.
It's only when the user clicks the element that a match would be found for $('#tree li.closedNode').
So we tell its parent which exists to look for the click event for both matching descendants. As soon as one MATCHING descendant pops into existence (when you change the class name), the event triggers.
From http://api.jquery.com/on/
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next.
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.
In your original code you set up the correct selector, but there were no matches at that time. So, #tree which exists at the time, can store the events made on its descendants.
Just one other thing
Why hide and show the list elements with jQuery? You're adding a class anyway so you could do that with CSS.
I'm trying to append some html to a page when a div is clicked on, then when any other part of the page is clicked on (except the newly attached div and the div that was clicked that attached it) remove the attached div. For some reason my :not() selector isn't working as I'd expect it to.
$("*").on("click", "body:not(._tlh_dropdown, ._tlh_dropdown_content)", function () {
// ... remove previously attached div
});
http://jsfiddle.net/qUHAB/5/
How can I remove this div when anything is clicked on except for the two classes _tlh_dropdown and _tlh_dropdown_content?
Well:
$("*").on("click", "body:not(._tlh_dropdown, ._tlh_dropdown_content)", function () {
is almost certainly not what you want. That adds an event handler for every element on the page, asking it to check for events from the <body> to have bubbled up. It kind-of makes no sense.
And
$("body").on("click", "*:not(._tlh_dropdown, ._tlh_dropdown_content)", function () {
will have problems with your test page because there's nothing else in the <body> but your header.
Change it to the second thing above (like it was in your original question), and then add a <div> with some text in it after the content that's there, and then click in that. Alternatively, change it to:
$(document).on("click", "*:not(._tlh_dropdown, ._tlh_dropdown_content)", function () {
and that'll catch events bubbling up from the <body>.
edit — if you go with $(document), it'd also be a good idea (especially if you want it to work :-) to add an "event" parameter to the handler functions and, in each, to call
event.stopPropagation();
In the first event handler (the one that opens up the extra content), that will prevent the second handler from running when the "click" on the header bubbles up to the body. For the second handler, stopping propagation isn't as important but it'll avoid redundant attempts to close the added content.
edit some more — see the comments below; the "close" handler has some subtleties that make implementing it with the "on" selector approach kind-of problematic.
I use jQuery to add some HTML to the DOM. After the insertion I would like to create an eventhandler which is called on keyup and clicks on the link added to el. However, jQuery does not find the a element as it was added after loading the page.
var el = $("#name");
// add content to el
$(document).keyup(function(e) {
el.find('a').click();
});
How can I update the DOM in el? I know that there is on() (and its predecessors) in jQuery. However, they do not help me as the event is not registered on the added element itself, but on the document and another event just happens on the newly added element. Any ideas on how to solve this?
Thanks to the response of #Johan I was doing further debugging and found the solution:
el.find('a')[0].click();
So the real problem was not the changing DOM but the click() event that apparently can only be applied to a single element and not to a list of only one element.
Some further discussion about click() not firing can be found here: Can I call jquery click() to follow an <a> link if I haven't bound an event handler to it with bind or click already?
With twitters Bootstrap I've created a button group with radiobox behaviour to let the user choose between the different states. This works out of the box as supposed.
I arranged a jsFiddle with the example here: http://jsfiddle.net/jpxWj/
What I tried (and want) is that the pressed state can be removed when I click the active button second time.
I tried with jQuerys removeClass() to remove the active class from the btn classes but it won't work. (I also tried removing with .on() but this just keeps the active always hidden/removed)
Here you go, quite an unknown event phenomenon, in my opinion. You can read more about it here.
Edit:
To ellaborate, the reason why a simple .removeClass doesn't work, is because there are multiple listeners, listening to the same event. So when the click event is fired, a normal .removeClass would remove the class, but then the Twitter Bootstrap handler would add it again! To prevent any other handlers from being executed after yours, you can do e.stopPropagation. However, this does not stop the handlers attached to the same element as yours, it only stops the ones further up the tree. To completely make sure no other handlers are executed after yours, you can use event.stopImmediatePropagation().
Bootstrap 3 Update:
$('body').on('click', '.btn-group .btn.active',function(e){
e.preventDefault();
e.stopImmediatePropagation();
$(this).find('input').removeAttr('checked');
$(this).removeClass('active');
});
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">
<img src="img/nurse.jpg" alt="Find the nurse" />
</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.
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
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.
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,
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);
}