is tr element unclickable? - javascript

When I bind a handler to a element
$('tr').on('click', handler)
And Then when I trigger the element's click event, nothing happen
$('tr').trigger('click')
instead the element within the can response to the event
$('tr td:first').trigger('click')
So does it mean that <tr> element isn't clickable?

What does your handler function do? It seems to work fine for me:
function handler(e){
alert(e.target);
}
// attach event
$('tr').on('click', handler);
// manually trigger click
$('tr').trigger('click');
Live example.
<tr>'s are DOM objects, so you should be able to attach events to them

stopPropagation() will also help.
$('tr').click(function(e){
e.stopPropagation();
});

Related

Trigger event on parent originating, bubbling up from child

If I have a <div class="timely"></div> containing a table, in that table is a <th class="prev"><i>previous</i></th>...Chrome dev tools say there is an event listener on the <th>, but Firefox dev tools points out it is not on the <th>, but the parent .timely, which Chrome also points out when viewing what is in the handler for this event.
What I am trying to do is replicate what happens on click, to happen on keyup. It doesn't seem as simple as, in jQuery:
$('.timely th').each(function(){
$(this).on('keyup', function(){
$(this).trigger('click');
});
});
Because the event handler is on the .timely and it is listening from where the event bubbled up from when executing the code.
How can I replicate the click event on keyup of .timely with the context of it bubbling from the <th>?
First, note there's no reason for your each loop (unless you're doing something else in it you haven't shown). Remember that jQuery is set-based, so $("selector").on(...) sets up the handler on all elements in the set.
Re your question: Accept the event argument and use its target property as the element on which to trigger:
$('.timely th').on('keyup', function(e) {
$(e.target).trigger('click');
});
Or if you want to handle it up on .timely instead of on the th in .timely, just change the selector and use the delegating form (assuming you only want this for the th elements):
$('.timely').on('keyup', 'th', function(e) {
$(e.target).trigger('click');
});
It's tricky to get keyup on a th element, of course; the only way immediately coming to mind is to put an input element in the th so the keyup bubbles:
$('.timely th').on('keyup', function(e) {
console.log("keyup");
$(e.target).trigger('click');
});
$('.timely th').on('click', function(e) {
console.log('click');
});
<div class="timely">
<table>
<tbody>
<tr>
<th>
<input type="text">
</th>
</tr>
</tbody>
</table>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You haven't said why you want to trigger click on keyup, but if it's just to run the click event handler, I don't recommend doing that. Instead, just use the same function for both the keyup and click handler. You can hook multiple events just by space-delimiting them in .on (.on("click keyup", ...)), or use a named function and refer to it where you hook up your click and keyup handlers.
Chrome dev tools say there is an event listener on the <th>, but Firefox dev tools points out it is not on the <th>, but the parent .timely
If you don't want to see handlers attached to ancestors, untick the Ancestors box in the Event Listeners tab:
But note that in your example code, the handler is definitely on the th, not the ancestor .timely element.
this jquery magic may not will work fast
$('.timely th').each(function(){
$(this).on('keyup', function(){
$(this).trigger('click');
});
});
you can abstract function that you want use on click and on keyup
function clickKeyupHandler (e) {
// ...
}
// somewhere when you use it use same functions to handle click and keyup
// $('.timely').on('click', clickKeyupHandler);
$('.timely').on('keyup', 'th', clickKeyupHandler);

JQuery selector still working after I remove the class?

I have two jquery functions that work together, one depends on a class, another removes the class.
Once it is removed I would expect the functionality to stop working, but it carries on?
Whats going on?
Here is the fiddle, try it out for yourself.
<div class="container disabled">
Go to Google
</div>
<label>
<input type="checkbox" />Enable link</label>
The JS
$('.disabled > a').click(function (e) {
e.preventDefault();
e.stopPropagation();
alert('should stop working');
});
$('input[type=checkbox]').change(function () {
$('.container').removeClass('disabled');
});
It looks like you want to be using delegated event handlers rather than static event handlers. Let me explain.
When you run a line of code like this:
$('.disabled > a').click(function (e) {
this installs an event handler on any objects that match the selector at that moment in time. Those event handlers are then in place forever. They no longer look at what classes any elements have. So changing a class after you install a static event handler does not affect which elements have event handlers on them.
If you want dynanamic behavior where which elements respond to an event does depend upon what classes are present at any given moment, then you need to use delegated event handling.
With delegated event handling, you attach the event "permanently" to a parent and then the parent evaluates whether the child where the event originated matches the select each time the event fires. If the child no longer matches the select, then the event handler will not be triggered. If it does, then it will and you can add/remove a class to cause it to change behavior.
The general form of delegated event handlers are like this:
$("#staticParent").on("click", ".childSelector", fn);
You ideally want to select a parent that is as close to the child as possible, but is not dynamic itself. In your particular example, you don't show a parent other than the body object so you could use this:
$(document.body).on("click", ".disabled > a", function() {
e.preventDefault();
e.stopPropagation();
alert('should stop working');
});
This code will then respond dynamically when you add remove the disabled class. If the disabled class is present, the event handler will fire. If it is not present, the event handler will not fire.
Working demo: http://jsfiddle.net/jfriend00/pZeSA/
Other references on delegated event handling:
jQuery .live() vs .on() method for adding a click event after loading dynamic html
jQuery .on does not work but .live does
Should all jquery events be bound to $(document)?
JQuery Event Handlers - What's the "Best" method
jQuery selector doesn't update after dynamically adding new elements
Changing the class after the event handler is bound has absolutely no effect as the event handler is not suddenly unbound, it's still bound to the same element.
You have to check for the class inside the event handler
$('.container > a').click(function (e) {
if ( $(this).closest('.container').hasClass('disabled') ) {
e.preventDefault();
e.stopPropagation();
}
});
$('input[type=checkbox]').change(function () {
$('.container').toggleClass('disabled', !this.checked);
});
FIDDLE
When the selector runs, it gets a list of elements including the one in question and adds a click event handler to it.
Then you remove the class - so any subsequent jQuery selectors wouldn't get your element - but you have already attached the event so it will still fire.
The selector you have used runs on the line you declared it - it isn't lazily initialized when clicks happen.

JQuery bind event after adding element dynamic

I have an issue after adding a element dynamically it doesn't have the click event, so i have the following:
$(".myclass > li").click(function () {
...
});
so basically when i click on LI element something should happen and it works.
But when i add a new LI element to myclass which is UL element, this newly added element doesn't call this function.
My question how do i rebind or bind this newly element to this function ..?
Because the other elements when i click on them they work, but only the new element doesn't ... i suppose it is that the binding happens on postback or somethnig but in my case there is no postback :/
You need to use Event Delegation. You have to use .on() using delegated-events approach.
i.e.
$(document).on('event','selector',callback_function)
In your case
$(document).on('click', '.myclass > li', function () {
...
});
OR if you want to apply to ALL list items:
$(".myclass").on('click', '> li', function () {
...
});
need to use event delegation to support dynamic elements
$(".myclass").on('click', '> li' function () {
...
});
Since the element is added after you bind the event, it doesn't have the handler attached and the bind function doesn't listen for any new elements that might be added.
Thus, you need to use event delegation. When an event triggers, it will bubble up all the way to the parent document. Using the jQuery .on() function you can listen for events that have bubbled up from their target.
In your case, you should use the following:
$(parent).on("click", "li", function() { ... });
The above will listen for click events that occur on li elements and bubble up to parent. Inside the event handler this will refer to the li element on which the event triggered. In case you don't know the parent, you can listen on document.
You can learn more about the .on() function here.

Unbinding click handlers on certain classes

I have a table cell that I want to be able to be clicked. But once it is clicked it will have the class ".clicked". When any table cell has this class, I do not want to be clickable. Is there any way to do this?
Also you can use .off() method to unbind any events.
$('td').on('click', function(){
$(this).addClass('clicked').off('click');
})
This is easily done by inserting some code at the top of the event handler.
$('td').click(function(e) {
if ($(this).hasClass('clicked')) {
e.stopPropagation();
e.preventDefault();
return;
}
// the rest of your code here
});
The other, more involved, way, is to use event delegation and only fire the function if the element doesn't have the class when it's clicked:
$('table').on('click', 'td:not(.clicked)', function() {
// your code here
});
You can use the .one() event registration method to do it, it will un-register the handler once the event is fired.
$('td').one('click', function(){
console.log('hanlded', this)
})
Another solution could be
$('table').on('click', ':not(.clicked)', function(){
console.log('hanlded', this)
})
Just add :not(.clicked) to whatever selector you're using to exclude clicked cells.

jQuery.on() both self and children

The .on() method in jQuery will either match on the matched element if no selector is provided or only on it's children if ther is a selector.
Is it possible to combine these two behaviours to end up with a single .on() statement that matches both the element and any specified children?
Example: http://jsfiddle.net/mwvdlee/YFF2k/
You can simply bind the event handler to the parent and use event.target [docs] to the get actual target element of the event:
$('.foo').on('click', function(event) {
console.log('click', event.target);
});
Since events bubble up (that's how event delegation works in the first place), every click on a descendant of .foo will trigger the event handler of .foo (unless the event was stopped somehow of course).
By default the events are bubbling up. Just avoid passing a delegate selector and attach the event-handler on the parent. When children will get clicked, the event should bubble up to the parent and the event will get fired.
DEMO: http://jsfiddle.net/YFF2k/2/
$('.foo').on('click', function (e) {
console.log('click', e.target);
});
you can try something like:
$('.foo').children().andSelf().on('click', function (event){
//something
});

Categories