When a user clicks on a <li>-element or on a child element of it, I want to add a class to this <li>-element.
This works fine, but for performance enhancement I decided to bind this event to the <ul>-element, so unbinding and binding this event is much faster in a list consisting of 1000 <li>-elements. The only change I thought I had to make was to replace this with event.target BUT event.target can also refer to a child element of a list item or even to a grandchild.
Is there an easy way to check this target element is part of a list item or do I need to walk the path from event.target till I reach a <li> element?
This is what I had before I decided to bind an event to the <ul> tag, which works but is not fast enough:
$('#list li').mousedown(function(){
$(this).addClass('green');
});
And this is what I have now which doesn't work properly, mousedown on a child element doesn't give the <li> another classname:
$('#list').mousedown(function(event){
if(event.target.nodeName == 'LI'){
$(event.target).addClass('green');
}
});
I wonder if my second way to achieve this is faster if there is not a simple solution to check if that target element is part of a list item...
Well, you could do all of this with the jQuery on tool:
$('#list li').on('mousedown', function() {
$(this).addClass('green');
});
You can read about what on does here: http://api.jquery.com/on/
You need to check if there is a LI tag in the parents of the target element.
All of the common frameworks have a way of determining this, it is up() in prototype, ancestor() in YUI3, and looking at the JQuery docs, it seems like it has a parent(), and parents() function that you can use for this.
See: http://docs.jquery.com/Traversing
Haven't used JQuery, but it I assume checking for $(event.target).parent('li') is the answer.
Related
I have a cascading menu with the following flow;
click on an item from menu-1
creates and updates menu-2 li elements
click on an item from menu-2
creates and updates menu-3 li elements
etc..
```
$firstMenu = $('.prime-menu');
$secondtMenu = $('.second-menu');
$thirdMenu = $('.third-menu');
```
As i'm traversing through different elems. within each menu, using find() comes as a blessing, the issue is that the script loads when no menu other than the first menu is created so $secondtMenu.find('.item-year').click(function (clickEvent) {}) is 0 length.
What are my options in JQuery to make my find() functions work on elements that are not loaded yet in the DOM?
I thought of creating an event listener, but I think there are more terse approaches than that.
You should use delegates when dealing with dynamic HTML. For instance, use an outer element like document or body to "start" your finds.
$(document).find(".prime-menu");
EDIT: Find and event delegation
The solution was to use find with event delegation. Example event.
$(document).find(".prime-menu").on('mouseenter', '.track-table tbody tr', function(){ });
You state that when you click on an item from menu-1 it creates and updates menu-2 li elements. In this function is where you should do your event binding. The DOMElement will exist in js before being added to the dom, and that is where your bindings should be set.
If you need help share this code with us I'm sure myself or someone will be able to help you sort it out.
Bind the click handler to the menu parent, not the actual menu items.
Something like this might work...
$("#menuparent").on("click",".item-year",function(event) {
var clicked_element = event.currentTarget;
});
Doing it this way, even if the element with class .item-year is added to the dom after the click event is bound, it will still register the click.
I’ve read many posts already on the $.each and newly added elements + event attachment. Many of the current Questions regarding this topic on StackOverflow don’t seem to work for me. $.on() is normally recommended since it allows us to append new elements and still maintain a single event listener + handler.
In my current code:
1.$(‘input[type="checkbox"]’).on(“change”, function(e){});
//I do a logical if-statement, if(this.checked) else
//With-in the if-statement I run $.each, however, once I have appended new element in this context a new li to the ul, it stops working.
Out of the curiosity has anyone encountered something like this before, and if YES, how have you folks solved this?
Some StackOverflow posts I have already seen:
jQuery $(element).each function doesn't work on newly added elements
jquery: dynamically appending li items to ul then adding click, but click runs through each li
Event binding on dynamically created elements?
Currently what you are using is called a "direct" binding which will only attach to element that exist on the page at the time your code makes the event binding call.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.
As you are creating elements.
You need to use Event Delegation. You have to use .on() using delegated-events approach.
General Syntax
$(document).on(event, selector, eventHandler);
Ideally you should replace document with closest static container.
Example
$(document).on('change', 'input[type="checkbox"]', function(){
//Your code
});
I'm trying to further my understanding of traversing and correctly using $(this).
I understand $(this) is used in reference to the context. However, say I have three items that are identical to each other (HTML-wise) and if a user clicks on an input, I want the events to not only happen for the item the user selected, but be able to access the parent element ".item" as well. This way, I can hide other elements within ".item" because, again, the context would be the "input" that the user clicked.
This is where I am confused. When a user clicks on the input ($('input').on('click', doSomething);), I am limited to the context of the input - nothing is inside the input, so I want to access other elements that are out of the input context.
I then try and use $(this) to say I only want THIS event to happen for THIS item only, not affecting ALL items.
Here is a code example: JSFIDDLE
I've tried researching this and I can't find much information on an instance like this so hopefully this could benefit others too. Feel free to make edits to the content / heading as I've tried to be as specific as possible.
To get the immediate parent(s) of the element(s) in a jQuery set: parent. (If your set has only one element, as $(this) will, that will give you that element's immediate parent.)
To find the closest element(s) to the elements(s) in a jQuery set matching a given selector, starting with the current element(s): closest. (If your set has only one element, as $(this) will, that will give you the first element matching a selector starting with that one element, then looking at its parent, then its parent, etc.)
This should be your click-handler code :
function doSomething(event) {
$(event.target).parent().find('ul').hide();
}
Is it better to attach the on() event to the document or a closer parent?
Note: Initially this question had another aspect and a different topic. It became obsolete really quickly (typo in the source code)
The best key for performance using jQuery is to use an id as the initial identifier. For example:
$('#my_id').on('click', 'tag.my_class', function () {
...
});
This allows jQuery to go straight to the container, and then begin trawling from there.
if you bind the "on" event to the closest parent will produce exactly what are you looking for, click function will works fine even if it is appended to document, but in future if you append any elements with class "clickable" will also get binded. so its always good practice to append the "on" event to closest parent rather than whole document.
if you want more specific you can use
$("ul.media-grid").on('click', 'li.clickable', function () {
alert("works")
});
as it will get the ul with the class "media-grid" and appends the event to the li's with class "clickable"
Can somebody please explain how "this" works in jQuery. I tried to find some information on the net, but because "this" is used a lot in his usual meaning I couldnt find anything good.
I would like to be able to change the background of a list element (<li>) onclick without giving each list element an id.
$('li').on('click.namespace', function() {
console.log(this); /* this is a reference to the DOM
element you clicked */
console.log($(this)); /* this is a jQuery reference to the
DOM element you clicked */
/* using jQuery reference you can change the background in this way */
$(this).css('background-image', 'url(...)');
});
$("li").click(function() {
$(this).css("background-color", "red");
});
Here is an example. $(this) refers to the JQuery object, this refers to the regular DOM object that was clicked on.
Did you find the click() documentation? It shows how you should use the click handlers and it has examples that even use $(this).
Here's an example:
$('li').click(function() {
$(this).attr("class", "clicked");
});
When one clicks on an item, this takes the value of the item being clicked on, that is the DOM element. $(this) gives you access to the jquery API.
If you set the onclick event on the li you can use $(this) to get the jquery object of the li, and then add a class eg. $(this).addClass("newBackground").
jQuery is kind enough to set the context of your function to the thing you're interesting in. In this case the <li> in question. But this is still a naked DOM element, you need to wrap it with $() to use jQuery methods on it.
$('li').on('click', function() {
$(this).css({background:'red'});
});
Sometimes you have to use a bound function (see jQuery.proxy()) as an event handler, in these cases you can access the current element differently, instead of this, you can use the event.currentTarget property, see http://api.jquery.com/event.currentTarget/