jQuery event delegation with .on (this reference) - javascript

Where does this reference to in a delegated .on event?
Example:
$('#foo').on('click', $('.bar'), function() {
console.log(this);
});
In the example this will reference to #foo. But how do i access the bar element that got clicked? I might have 5 bar elements and I want to know which one was clicked.
Thanks
Edit:
Sorry i changed #bar to .bar (since it exists multiple times).
The answer that i should just use '.bar' helped. But what if i have selector like this:
$('.bar').find('a');
How would i incorporate something like this?
This won't work: (cause this will reference to #foo)
$('#foo').on('click', $('.bar').find('a'), function() {
console.log(this);
});

Change it to this...
$('#foo').on('click', '.bar', function() {
console.log(this);
});
Now this will be the clicked .bar.
If you want a jQuery object then use $(this) as normal.
Edit
As per the change to question code, you'll need this...
$('#foo').on('click', '.bar a'), function() {
console.log(this);
});
That simply extends the click event handler to links inside .bar elements that may not exist at document.ready.

Two ways.
Use a string selector, not a jQuery object, when calling .on():
$('#foo').on('click', '#bar', function() {
console.log(this); // #bar
});
Specify a parameter name for the jQuery normalised event object, and use its target property:
$('#foo').on('click', $('#bar'), function(e) {
console.log(this); // #foo
console.log(e.target); // #bar
});
EDIT: Ignore the second option. jQuery doesn't accept a jQuery object for the selector, and as a result simply ignores it. You will not be setting up event delegation, you'd instead just be setting a static click event handler on #foo, which works due to event propagation.

An ID should be used once in a page. So you can add a class fooClass to your 5 elements and do :
$('.fooClass').onclick(function() {
alert("my bar element: " + $(this));
});
and do what you want with $(this).

Related

jQuery delete trigger conditionally

I was wondering if Javascript or jQuery have a way to delete an event listener. Let's say I want to make a function that I want to trigger only once, for example let's say I want to have a button that shows some hidden elements on the document, I would make this function (assuming the hidden elements have a hidden class that hides them):
jQuery('#toggler').click(function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
});
Simple enough, right ? Now, my actual problem comes in, I don't want jquery to run that function again and again each time the button is clicked, because the elements are already revealed, so is there a clean way to do it ? So, in this example after clicking the toggler multiple times I want to get only one console message.
I could do jQuery(this).unbind('click'), but this results into removing ALL triggers and I only want to remove the current trigger.
What I usually do when I face such scenarios is solve it like this (which is ugly and doesn't actually prevent code execution, but only handles the code's results) :
var toggler_clicked = false;
jQuery('#toggler').click(function() {
if(toggler_clicked) return;
toggler_clicked = true;
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
});
Also I don't want to use jQuery's one, because I will have the same problem when I'll need to delete the trigger conditionally, so if you can help please give me a dynamic answer.
Thanks in advance !
You have to name your function like that:
var myFunction = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
};
And bind it this way
jQuery('#toggler').click(myFunction);
Then you can unbind it with :
jQuery('#toggler').off('click',myFunction);
Without unbinding the other listeners
You can try this:
var myFunc = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
jQuery(this).unbind('click', myFunc);
};
jQuery('#toggler').click(myFunc);
This way of calling unbind is such that only the listener for myFunc handler is removed and not all the events connected to the click on the toggler.
I would use the .on() and its opposite .off() methods to attach/detach the event handler. It is the recommended way since 1.7 instead of the .bind() and .unbind() versions that became deprecated as of jQuery 3.0.
$("#toggler").on("click", function(event) {
console.log('Hidden elements are now shown');
$('.hidden').removeClass('hidden');
// if (/* Add your condition here */) {
$(this).off(event);
// }
});
$("#toggler").on("click", function(event) {
console.log('Hidden elements are now shown');
$('.hidden').removeClass('hidden');
// if (/* Add your condition here */) {
$(this).off(event);
// }
});
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="toggler">Toggle</button>
<div class="hidden">
HIDDEN
</div>
Try this
var myFunction = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
};
Add the event listener like this:
jQuery('#toggler').addEventListener("click", myFunction);
And remove it like this:
jQuery('#toggler').removeEventListener("click", myFunction);
So all together this will do the trick:
var myFunction = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
jQuery('#toggler').removeEventListener("click", myFunction);
};
jQuery('#toggler').addEventListener("click", myFunction);
more about the HTML DOM removeEventListener() Method
Jquery unbind function takes 2 parameters eventType and handler
You can put your event listener into separate function like this:
var clickEventHandler = function(){
//your logic goes here
}
After you add listener as reference:
jQuery('#toggler').click(clickEventHandler);
And then, later, anytime, anywhere you want you can unbind that specific handler:
jQuery('#toggler').unbind('click', clickEventHandler);
What i used to do in the past is toggle the click behavior using css classes, ex i used to set a click listener on the parent and delegate to all of the children something that jquery is doing now by default i believe. Anyway based on the css class it will trigger an event for ex.
$('.some-parent-element').on(
'click',
'the-behavior-css-class',
function() { // do stuff here.... }
)
Now if you want to remove this behavior you can just toggle the class of the element and it should do the job. ex
$('.some-parent-element').on(
'click',
'hide-me-on-click-or-whatever',
function() {
$(this).toggleClass('hide-me-on-click-or-whatever')
// perform the action
}
)
You can check if the element has the class hidden

Modify Dynamically Created (jQuery) Elements

I have this <li>, that when you click it, it creates another <li> before it (with a bunch of classes applied to it), which is all working great.. Problem is, I can't modify (via jQuery) the newly created <li> elements because they were created dynamically.
Currently, it is setup as:
$(".foo").on("click", function() {
//Blah blah blah
});
And I have already tried the code below instead, which still did not work.
$(".foo").on("click", function() {
//Blah blah blah
});
Thanks for your help in advance!
Since li are created dynamically for jQuery v1.7 tto attach an event handler for all elements which match the current selector, now and in the future.
$(document).on("click", ".foo", function() {
//Blah blah blah
});
Essentially if you are using 1.7 and above you're syntax is slightly incorrect for on.
Try this approach:
$("ul").on('mouseup', '.item', function() {
$(this).toggleClass("completed");
});
JS Fiddle demo.
The problem you were having is that the .item elements weren't present in the DOM at the point at which the mouseup event was bound to them. This approach binds the mouseup to the ul which does exist, and uses the on() method to listen for that event and, if the target element matches the selector (.item) passed to the method it implements the anonymous function (the third argument passed to the method).
If the target does not match that selector then the event either does nothing or contiunues to propagate through the ancestors.
Bind the event to an already present parent element:
$('#parent').on('click', '.foo', function() {
...
});
'#parent' would probably be a selector for your <ul> element.
JQuery 1.7+
I think it should work with the on() function:
$(".foo").on('click', function() {
// more code
});
Other
$(".foo").live('click', function(){
// more code
}
Does this work for you?:
$(function() {
var task =
$('<li class="editable todo-item">Double Click to Edit</li>');
$(document).on('click', '.todo-new', function() {
$('.todo-new').before(task);
});
$(document).on('dblclick', '.todo-item', function() {
$(this).toggleClass("todo-completed");
});
});

Using .on to bind to dynamically generated content

I am using Infinite Scroll to display some content and I'm having trouble binding some mouseenter/mouseleave events to the newly generated items.
I know that I need to bind .on to a container already existing on the page, but I'm having trouble figuring out the syntax to alter the current jQuery that toggles.
This is the current js:
$(document).ready(function() {
$('.grid-box .actions').hide();
$('.grid-box').on({
mouseenter: function () {
$(this).find('.actions').show();
},
mouseleave: function () {
$(this).find('.actions').hide();
}
});
});
The main container is #grid-container and each individual item is .grid-box. How can I alter the above so that the actions show/hide upon entering/leaving .grid-box?
I think I need something along the lines of this:
$('#grid-container').on('mouseenter mouseleave', '.grid-box', function(e) {
// some action
});
Exactly, this is known as event delegation and it waits for the event to bubble up then matches the event based on the selector. This is much more efficient because there is only one handler registered rather than N times the number of elements. Also, you only have to bind once rather than every time the dynamic content is changed.
$('#grid-container').on('mouseenter', '.grid-box', function(e) {
// some action
}).on('mouseleave', '.grid-box', function(e) {
// some action
});
The selector as the second argument will still work:
$('#grid-container').on({ ...}, '.grid-box');
http://jsfiddle.net/QkFTz/1/
An alternate method would just be to bind them separately, which I personally think is clearer:
$("#grid-container").on('mouseenter', '.grid-box', function () {})
.on('mouseleave', '.grid-box', 'function () {});

accessing element attributes with mootools selector

I'm trying to attach a mouseover event to all img elements of a gallery in a page (using Mootools). This is easy enough using something like
$$('img.mygalleryclass').addEvents({
mouseover: function(){
alert(id);
}
});
My question is, how do I alert the id of the element referenced in the $$ 'loop'? That "alert(id)" returns an error every time since id is not defined.
Thanks!
Pass the event argument to the mouseover function and then get the id of the target:
$$('img.mygalleryclass').addEvents({
mouseover: function(e) {
alert(e.target.id);
}
});
Here's an example.

Changing the onclick event delegate of an HTML button?

How do you change the JavaScript that will execute when a form button is clicked?
I've tried changing its onClicked and its onclicked child attributes like so:
$('mybutton').onClick = 'doSomething';
and
$('mybutton').attributes["onclick"] = 'doSomething()';
Neither seem to work. My other options are:
To have two buttons and hide one and show the other.
To have it directed to a function that evals a string and change the string to the function I want to execute.
Neither seem very elegant.
I'm using Prototype as a js library so it that has any useful tools I can use them.
If the original onclick event was set through HTML attributes, you can use the following to overwrite it:
$("#myButtonId").setAttribute("onclick", "myFunction();");
For Prototype, I believe that it would be something like this:
$("mybutton").observe('click', function() {
// do something here
});
EDIT: Or, as it says in the documentation, you could simply specify the function you want to call on click:
$('mybutton').observe('click', respondToClick);
function respondToClick(event) {
// do something here
}
But this is all, again, Prototype-specific.
Using the Prototype framework you can do:
Event.observe("mybutton", "click", clickHandler);
or:
Event.observe("mybutton", "click", function() {
alert("Button clicked!");
});
or:
$("mybutton").observe("click", clickHandler);
or:
$("mybutton").observe("click", function() {
alert("Button clicked!");
});
See the Event class documentation
The general way to set an onclick handler in javascript is to set onclick to a function, by passing it the name of a function directly, not in a string. So if myButton is set to a DOM Element, you would write:
myButton.onclick = doSomething;
So when you click the 'mybutton' button, the doSomething function will be called as doSomething(). For anonymous functions, you can write:
myButton.onclick = function() {
alert("myButton was clicked!");
};
In JQuery it's
$("#myButtonId").click(myFunction);
function myFunction(){
alert("Clicked");
}
Or if you want to put the function inline:
$("#myButtonId").click(function(){
alert("Clicked");
});
If you are using JQuery firstly make sure you use the relevant selector prefix (IE: If your using the Id of the element put a # in front of it). Secondly it's the click method to assign a callback to the click event.
Last I used Prototype, it was something like this:
Event.observe('mybutton', 'click', doSomething);
By the way, your examples might've even worked if you didn't quote the function names.
EDIT: Yes, Element.observe(element, eventName, handler) and someElement.observe(eventName, handler) also work. And don't quote the handler name - you want to pass the function not a string!
I found a solution for your issue with prototype under firefox:
$("#myButtonId").writeAttribute('onclick', ''); // first remove the attribute
$("#myButtonId").observe('click', function () { ... }); // then add the event

Categories