How to apply multiple events to the same function - javascript

I'm not the best at this jquery stuff. But I'm trying to seperate the action from the function so I can apply multiple events that cause the same function. Unfortunately this isn't working. Anyone know why?
Updated Function, but still errors
$(document).ready(function() {
var $info_items = jQuery('.checkbox.has_info, .has_info');
$info_items.click(function(event) {
$(this).show_text(event);
});
// I suspect it has something to do with this initalizer of the function here
jQuery.fn.show_text = function(event){
var $info_item = jQuery(this);
$info_items.filter(function(index){
return $(".hidden_text").css("display","block");
}).not($info_item).parent().next().next().hide("slow");
$info_item.parent().next().next().show("fast");
});
});

What is e, the event? You need to name the event argument to the click() function to use it. Also, to invoke show_text such that it has a this, you need to invoke it on an element:
$info_items.click(function (event) {
// 'this' is the element in $info_items which was clicked
// invoke show_text on the element in question
$(this).show_text(event);
});
You also have an extra ) on your final }); line.

You can use jQuery bind to attach several events to a single function.
$('#whatever').bind('mouseover focus click', function() {
your_custom_function();
});

Are you looking for something like this?
var handle = function(event) {
$(event.currentTarget).show_text(event);
};
$info_items.bind('click blur', handle);

Related

jquery .off(): how to remove a certain click handler only?

I've an element with two handler bound to it:
<button class="pippo pluto">
push me
</button>
$('.pippo').on('click', function () {
alert("pippo");
});
$('.pluto').on('click', function () {
alert("pluto");
});
I'm trying to .off() only one of them, but the syntax eludes me :-( I'm trying with something among the line of..
<button class="dai">
remove
</button>
$('.dai').on('click', function () {
$('.pippo').off('click');
alert("ok, removed");
});
but this removes both the handler. So I'm trying with...
$('.pippo').off('click .pippo');
but then nothing gets removed.
So I removed the middle space:
$('.pippo').off('click .pippo');
but back to square 1: both handler gets removed.
The right syntax would then be... ?
https://jsfiddle.net/6hm00xxv/
The .off(); method allows you to target multiple selectors as well as a specific event.
$('.pippo').off() would remove all events for the .pippo selector.
$('.pippo').off('click') would remove all click events for the .pippo selector.
$('.pippo').off('click', handler) would remove all click events with that handler for the .pippo selector.
In your case the handler used to add the event listener was an anonymous function so the handlercannot be used in the off() method to turn off that event.
That leaves you with three options, either use a variable, use a namespace or both.
Its quite simple to figure out which one to use.
if( "The same handler is needed more than once" ){
// you should assign it to a variable,
} else {
// use an anonymous function.
}
if ( "I intent to turn off the event" && ( "The handler is an anonymous function" || "I want to turn off multiple listeners for this selector at once" ) ){
// use a namespace
}
In your case
your handler is only used once so your handler should be an anonymous function.
you wish to turn off the event and your handler is anonymous so use a namespace.
So it would look like this
$('.pippo').on('click.group1', function () {
alert("pippo");
});
$('.dai').on('click', function () {
$('.pippo').off('click.group1');
alert("ok, removed");
});
It would work just as well to assign you handler to a variable if you prefer.
This allows you to specify which selector, eventType and handler to remove.
var pippo_click = function (e) {
alert("pippo");
});
$('.dai').on('click', function () {
$('.pippo').off('click', pippo_click);
alert("ok, removed");
});
But as a rule you shouldn't create variables if they're not needed.
One easier alternative with jQuery is to define a namespace for your click events:
$('.pippo').on('click.first', ...);
$('.pluto').on('click.second', ...);
// Remove only the pippo listener
$('.pippo').off('click.first');
Note that your classes pippo and pluto refer to the same element so using one or the other will not change anything.
https://jsfiddle.net/6hm00xxv/2/
Ok, solved. I just had to bind the handler to document:
function showMsg(text) {
alert("showMsg called with text: " + text);
};
$(document).on('click', '.pippo', function () {
showMsg("pippo");
});
$(document).on('click', '.pluto', function () {
showMsg("pluto");
});
$('.dai').on('click', function () {
$(document).off('click', '.pippo');
alert("ok, removed");
});
https://jsfiddle.net/6hm00xxv/1/
Because you are calling .off for click event. It is removing all possible click events on that selected element. The trick is to define a handler and remove that particular handler only.
function showPluto() {
showMsg("pluto");
};
function showPippo() {
showMsg("pippo");
};
function showMsg(text) {
alert("showMsg called with text: " + text);
};
$('.pippo').on('click', showPippo);
$('.pluto').on('click', showPluto);
$('.dai').on('click', function() {
$('.pippo').off('click', showPippo);
alert("ok, removed");
});

jQuery - Select All inputs and Bind Function

What's the most efficient way to select all input elements on a form and then attach a function to each which fires on focus out?
I am thinking along the lines of
var allInputs = $("form").each(function(){
$(this).find(':input').focusout(focusOutFunction);
});
var focusOutFunction = function() {
// do focus out things here
};
but not quite there yet.
Any advice would be much appreciated!
What about just:
$("form :input").blur(function() { });
Perhaps use event bubbling and delegation to catch the event on the inputs common container?
eg:
$('div.container').on('blur', function (e) {
console.log('I haz blurrd: ', e.target);
});

Javascript - Add specific keypress event inside a loop

I am attempting to assign a keypress event to an element within a for loop. I know that there are issues with assigning events while in a for loop dynamically, and I have solved that for the "click" event however I am at a loss for how it should work for the keypress. (probably because I don't really understand how the "click" one works to begin with... closure avoidance is not something I fully get)
The basic setup is that there is a for loop that will print out a number of different textareas and a div underneath them. Pressing the div will send the text in the text area to the right person. What I would like to have happen is that the same message should be sent if the enter button is pressed within the text area.
for( var i in people){
var message = $('<textarea></textarea>').appendTo(container);
message.on( "keypress", function(e) {
if(e.keyCode==13){
// code does make it in here ...
sendMessage(people[i].name); // but this never gets run
}
});
var messageButton= $('<div>Send</div>').appendTo(container);
messageButton.on( "click", sendMessage(people[i].name) );
}
var sendMessage = function(to) {
return function(){
/* do the sending of the message to the right person */
}
}
Can anyone help me understand the following?
Why does the click function work in the first place? I am not understanding why we have to put return around the function block.
Why doesn't the keypress function work similarly?
On a more general level, how does keypress work to begin with. The function(e) should not work because 'e' isn't anything, where does that even get set?
The problem with keypress in the code is that it will always send the message to latest person in people as at the moment when it is executed, i will have the latest value in it.
I probably would use forEach instead:
people.forEach(function (person) {
var message = $('<textarea></textarea>').appendTo(container);
// you can use keypress - http://api.jquery.com/keypress/#keypress-eventData-handler
// see the examples in the reference
message.keypress(function (e) {
if (e.which === 13) {
// here you should invoke the function returned by the sendMessage
sendMessage(person.name)();
}
});
var messageButton= $('<div>Send</div>').appendTo(container);
messageButton.click(sendMessage(person.name));
});
with this approach you do not need to wrap the function in the sendMessage and can just call the original function in the corresponding event handler.
Clean example using jQuery. You should read more about jQuery and closures for iterations so you can easily understand what is going on.
$.each(people, function (person) {
var $message = $('<textarea></textarea>').appendTo(container);
var $button = $('<div>Send</div>').appendTo(container);
var send = sendMessage(person.name);
// Keypress handler
$message.keypress(function (e) {
if (e.which === 13) { // on enter do the following
send();
}
});
$button.click(send);
});
Here's another solution using a handwritten closure:
http://jsfiddle.net/M5NsS/1/
var people = {
'p1': {
name: 'john'
},
'p2': {
name: 'bob'
},
'p3': {
name: 'jim'
}
};
var container = $('#container');
for (var i in people) {
(function (name) {
var message = $('<textarea></textarea>').appendTo(container);
message.keypress(function (e) {
if (e.keyCode == 13) {
sendMessage(name);
}
});
var messageButton = $('<div>Send</div>').appendTo(container);
messageButton.click(function () {
sendMessage(name)
});
})(people[i].name);
}
function sendMessage(to) {
console.log(to);
}
As others have stated, the issue is that the event is bound with the last reference to 'i' in the loop. Using a closure solves this issue while still allowing you to use your for..in loop.
Another thing to note is that if you are not dynamically appending these elements to the DOM after binding, there is no reason to use jquery's .on(). You can directly bind .keypress() and .click() handlers to the elements, as seen in my fiddle and on #AlexAtNet's answer.
But it's clunky, and I would just use jquerys $.each as others have already suggested.

Adding an on event to an e.currentTarget?

A variety of elements on my page have the content editable tag.
When they are clicked I do this:
$('[contenteditable]').on('click', this.edit);
p.edit = function(e) {
console.log(e.currentTarget);
e.currentTarget.on('keydown', function() {
alert("keydown...");
});
};
I get the current target ok, but when I try to add keydown to it, I get the err:
Uncaught TypeError: undefined is not a function
It's a native DOM element, you'll have to wrap it in jQuery
$(e.currentTarget).on('keydown', function() {
alert("keydown...");
});
e.currentTarget should equal this inside the event handler, which is more commonly used ?
It's a little hard to tell how this works, but I think I would do something like
$('[contenteditable]').on({
click : function() {
$(this).data('clicked', true);
},
keydown: function() {
if ($(this).data('clicked'))
alert("keydown...");
}
});
Demo
First issue is you are trying to use jQuery methods on a DOM element. Second issue is I do not think you want to bind what is clicked on, but the content editable element itself.
It also seems weird to be adding the event on click instead of a global listener. But this is the basic idea
$(this) //current content editable element
.off("keydown.cust") //remove any events that may have been added before
.on('keydown.cust', function(e) { //add new event listener [namespaced]
console.log("keydown"); //log it was pressed
});
Edited: I had a fail in code. It works fine now.
Getting your code, I improved to this one:
$(function(){
$('[contenteditable]').on('click', function(){
p.edit($(this));
});
});
var p = {
edit: function($e) {
console.log($e);
$e.on('keydown', function() {
console.log($(this));
alert("keydown...");
});
}
}
You can check it at jsFiddle
You need to wrap the e.currentTarget(which is a native DOM element) in jQuery since "on" event is a jQuery event:
$(e.currentTarget).on('keydown', function() {
alert("keydown...");
});
EDIT:
$('[contenteditable]').on('click', p.edit);
p.edit = function(e) {
$(e.currentTarget).on('keydown', function() {
alert("keydown...");
});
};
You're defining p.edit AFTER $('[contenteditable]').on('click', p.edit); resulting in an error since p.edit doesn't exist when declaring the on.
In case you don't know, you are defining p.edit as a function expression, meaning that you have to define it BEFORE calling it.

How do I add a click handler to a class and find out which element was clicked?

I have been using the following method for adding a click event to an id, I was wondering if I could do the same with a class.... I have a number of items (which are created in a for each loop) and I need to be able to click them and then pickup which was clicked... here is my existing code
$('submit-button').bind('click', submit_click);
function submit_click() {
alert('I am clicked');
}
I was wondering if there is some way to pass in a variable into my function for the click so i can check the ID?? or similar
hence this
function submit_click(element) { // notice element
alert(element + ' clicked');
}
Any help really appreciated
Thank you
EDIT
I have tried the following and in debug "elem" is undefined...
$('.clear').bind('click', clear_click($(this)));
function clear_click(elem)
{
alert(elem.attr("id"));
}
WORKING SOLUTION
I have the working solution but I don't fully understand why, I would love to know why it works..
First of all I tried
$('.clear').bind('click', clear_click($(this)) );
This seemed to work "BUT" when I loaded the page it enter the "clear_click" method without being clicked - strange...
Then I tried this..
$('.clear').bind('click', function() { clear_click($(this)) } );
This works great! But I don't understand why I must pass a function and then within this function call my clear_click.
Can anyone explain why 1 works and the other doesn't?
Whenever I need to call a callback function or similar I should first open a function() and then call the method inside the function?
$(".yourclass").click ( function() {
$(this).attr ( "id" ); //S(this) returns the current element
});
and you can code like this
$('.yourclass').bind('click', function() { submit_click($(this)) });
function submit_click(elem)
{
alert ( elem.attr ("id" ) );
}
Edit
$('.clear').bind('click', function() { clear_click($(this)) });
function clear_click(elem)
{
alert(elem.attr("id"));
}
This will work fine for you.
Update
To answer your second question:
You can bind a function as a second argument when using the click event, but you cant bind a function and apply arguments. On the other hand, there is no need to send this as an argument to the clear_click function since the this keyword inside the function refers to the element itself:
So this works in your case:
$('.clear').bind('click', clear_click);
function clear_click() {
alert(this.id);
}
Sending this as an argument is not needed and bad coding:
$('.clear').bind('click', clear_click(this));
In the event handler, the first argument is the event object. You can extract the clicked element from that object using currentTarget or target. In jQuery, this always refers to the currentTarget in the event handler context:
var handler = function(e) {
var id = this.id; // this == e.currentTarget
}
$('submit').click(handler); // .click(fn) is shorthand for .bind('click', fn)
More examples:
$('submit').bind('click', function(e) {
console.log(e.target) // the target that was clicked on
console.log(e.currentTarget) // the element that triggered the click
console.log(this) // the same as above
});
Just add $(this) to your function, You don't need to send any parameters because you are still in the context of the clicked element.
function submit_click() { // notice element
alert($(this).attr('id') + ' clicked');
}
When you bind a handler to a function, the clicked element will be the first argument
$('.submit-button').click(submit_click);
function submit_click(element){
//element is the .submit-buttom element
alert(element+' was clicked');
alert($(element)+' was clicked');
}
This should work:
$('.submit-button').bind('click', submit_click($(this)));
function submit_click(element) { // notice element
alert($(element).attr("id") + ' clicked');
}

Categories

Resources