I'm using jQuery and I have a function that serves as an event callback, and so in that function "this" represents the object that that captured the event. However, there's an instance where I want to call the function explicitly from another function - how do I set what "this" will equal within the function in this case?
For example:
function handleEvent(event) {
$(this).removeClass("sad").addClass("happy");
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
handleEvent(e); // in this case, "this" will be the window object
// but I'd like to set it to be, say, the input in question
}
}
Use apply call.
handleEvent.call(this, e);
Just parameterize the function you're interested in:
function doStuff(el) {
$(el).removeClass("sad").addClass("happy");
}
function handleEvent(event) {
doStuff(this);
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
doStuff(this);
}
}
Use
e.target
I'd advice you re-factoring your function as a jQuery plugin.
But here's a quick Fix:
handleEvent.apply(this,e) //transfers this from one scope, to another
If you're simply looking to call a single event handler as if it were being triggered normally, apply/call will work fine. However, depending on your needs, it may be more robust to use the zero-argument version of jQuery's click() function, which will trigger all click handlers for that element:
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
$(this).click(); // simulate a click
}
}
Related
Just wondering, is this a valid way to define an explicit function inside JavaScript's addEventListener function so that it could be removed at any time using removeEventListener?
var somefunction;
window.addEventListener('load', somefunction = function(){
//do something
}, false);
window.removeEventListener('load', somefunction, false);
In other words, is it ok to define a variable somefunction and then assign an anonymous function to it inside addEventListener, instead of defining somefunction outright from the get go? It seems to work in FF and Chrome, but just wanna make sure this is officially valid JavaScript syntax.
Yes, it will work. An assignment is an expression -- it assigns to the variable and also returns the value that it assigned.
Personally I think this is a confusing way to write it. If you're refer to the function by name, put the definition where you define the name, not where you use it. In particular, if you try to do this twice, you'll have a problem because each event listener will have a different function, but it has the same name.
window.addEventListener('event1', somefunction = function() {
//do something
});
window.addEventListener('event2', somefunction = function() {
//do something
});
Now you can only remove event2, because somefunction no longer refers to the function that was added to event1.
Calling removeEventListener() with arguments that do not identify any
currently registered EventListener on the EventTarget has no effect.
So as long as removeEventListener has say a 'click' event as an argument, any one eventListener registered to the 'click' event will be removed. This is evident in OP's case, therefore it is feasible according to the criteria previously mentioned.
The following Snippet demonstrates a registered eventListener added to #target1 to listen for the 'click' event. It will be functional until removeEventListener() is called to remove the eventListener within 4 seconds. Notice that this particular removeEventListener's arguments are:
the event object............: click
a named function..........: eventLog()
and it's capture boolean: false
The identifying argument is 'click' and the target.event is #target that allows removeEventListener() to identify it's target.
SNIPPET
var eventLog;
var tgt1 = document.getElementById('target1');
var term = document.getElementById('btn');
tgt1.addEventListener('click', eventLog = function(e) {
console.log('target1 has been clicked');
}, false);
setTimeout(function() {
tgt1.removeEventListener('click', eventLog, false);
eventLog('Target1 eventListener is removed');
}, 4000);
function eventLog(str) {
console.log(str);
}
#target1 {
border: 2px solid red;
}
<p>Start clicking TARGET1 several times and you'll notice that each `click` event is firing as displayed in the console. Within 4 seconds, TARGET1's eventListener should be removed.</p>
<div id='target1'>TARGET1</div>
I was wondering how to use the $(this) selector in a function. I have tried multiple ways found on the internet but none seem to work.
Here's an example of what I'm trying to do
function bobsCar() {
$(this).toggle();
}
$('p').click(function() {
bobsCar();
});
Another option is to execute the function with a custom context like.
function bobsCar() {
$(this).toggle();
}
$('p').click(function() {
bobsCar.call(this);
});
In your case since you are calling bobsCar without a context, this inside it refers to the window object that is why it is not working.
Function.call()
function bobsCar() {
$(this).toggle();
}
jQuery('p').click(function() {
bobsCar.call(this);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>click me</p>
You need to understand JavaScript contexts. By default if you call a method inside your click callback, it will use the global context (in this case window - try console logging this in your broken function), not the one in the callback. You can use call or apply to specify the context (in this case this refers to the DOMNode element in the callback, so we pass the same context to the function and it works).
This is a good article on the topic: http://yehudakatz.com/2011/08/11/understanding-JavaScript-function-invocation-and-this/
The value of this inside the click event handler is not a string representation of a selector. It is a DOM node.
If you want to override the normal value of this for a function, you can specify it with call or apply.
bobsCar.call(this);
You could pass it as an argument instead.
bobsCar(this);
function bobsCar(domNode) {
$(domNode).toggle();
}
You should probably just use the function as the event handler in the first place though.
$('p').click(bobsCar);
You cannot directly use this in called function. You must have to pass selected object as function argument.
function bobsCar(element) {
$(element).toggle();
}
$('p').click(function() {
bobsCar(this);
});
This inside the function no longer reefers tot he 'p' tag, you could pass it
function bobsCar(el) {
el.toggle();
}
$('p').click(function() {
bobsCar($(this));
});
In JavaScript the $(this) is a context-pointer. It gives you the top-most context that is placed on the stack.
function bobsCar(elm) { console.log(elm);
$(elm).parent().toggleClass(); }
$('p').click(function() { var $this=$(this); bobsCar($this); });
jsfiddle.net/q325d6zw
I would like to add a click event listener to a function but would only like it to happen once. How could i do this?
I would like to stay clear of JQuery as well if it is possible please.
EDITED
As the answers that I am getting for this are fully satisfying my need i thought i may make it a bit more clear with context.
I am writing a function to draw a rectangle, first with one click on a button to initiate the rectangle function. Then there are two click event listeners in the drawRectangle function. These are the events i would like to happen only once in the function. Allowing the user to then create another rectangle if they click on the rectangle initiation button again.
Use modern JavaScript!
EventTarget.addEventListener("click", function() {
// Do something cool
}, {once : true});
A Boolean indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
- MDN web docs
All modern browsers support this feature
Other reference
You have to use removeEventListener once the event is fired once. However, removeEventListener takes a function as argument, which means you need to declare a named function, add it with addEventListener, and have it removing itself. Example:
function foo() {
// do things, then
removeEventListener('click', foo);
}
addEventListener('click', foo);
function one(el, type, fn) {
function handler(event) {
el.removeEventListener(type, handler);
fn(event);
}
el.addEventListener(type, handler);
}
// use it like
one(window, 'resize', function () {
alert("This triggers just once");
});
Example: http://jsfiddle.net/6njpem7x/
The other answers are correct in that this can be achieved with a named function, but you don't need to declare the function separately. You can use a named function expression:
element.addEventListener("click", function handler(event) {
this.removeEventListener("click", handler);
// ...
});
An alternative, though less optimal, approach is to keep around a variable that keeps track whether the handler was executed:
var wasExecuted = false;
element.addEventListener("click", function(event) {
if (wasExecuted) {
return;
}
wasExecuted = true;
// ...
});
The variable needs to be declared outside the handler but within scope, so that its value persists across event triggers.
Combination of addEventListener and removeEventListener:
element.addEventListener("click", clickFunction);
function clickFunction(e) {
console.log("clicked");
element.removeEventListener("click", clickFunction);
}
jsFiddle
something like this
var el = document.getElementById('something');
el.addEventListener('click', doSomething);
function doSomething() {
el.removeEventListener('click', doSomething);
//code
}
Inside event handler you can use universal: e.target.removeEventListener(e.type, arguments.callee)
Or you can make special function for creating "one time" event listeners:
function oneTimeListener(node, type, callback) {
// create event
node.addEventListener(type, function(e) {
// remove event listener
e.target.removeEventListener(e.type, arguments.callee);
// call handler with original context
// as it happens with native addEventListener
return callback.call(this, e);
});
}
oneTimeListener(document.getElementById("myElement"), "click", myHandler);
You can set a cookie after first click:
document.cookie="click=1; expires=.......";
and add condition to listener - if cookie is set, you omit that.
Another simple solution which I'm using is to add a dummy class to the element to which we are listening so that it will not fire again.
const myButton = document.querySelector('#my-button:not(.init)');
myButton.addEventListener('click', (e) => {
e.preventDefault();
myButton.classList.add('init');
});
If I originally have a click event handler in jQuery like this
jQuery('#btn').click(_eventHandler);
Which then handles the event like
function _eventHandler(e){
jQuery(this).text('Clicked');
}
then the this keyword exacts as an alias to the DOM element of the button that was clicked, correct?
But now, I need to change this logic so there is a flag to check for something else like
jQuery('#btn').click(function(e){
if(blah){
_eventHandler(e);
}else{
_dosomethingElse(e);
}
});
then will the this keyword in _eventHandler still work correctly? I basically need to do a check before the _eventHandler is called, but I do not want to change the actual function for the _eventHandler and place this logic inside there. Will this still work?
If you want this set in your functions, you can use .call() to cause it to be set accordingly:
jQuery('#btn').click(function(e){
if(blah) {
_eventHandler.call(this, e);
} else {
_dosomethingElse.call(this, e);
}
});
This allows you to use the same function either called by yourself or as a direct event handler because this and the arguments will be set identically.
Every function has both a .call() and .apply() method which allow you to set the this value when calling a function. You would use .call() when you have a specific number of arguments to pass and you would use .apply() if you have an array of arguments (often of unknown length). See MDN for more info.
you can pass its reference in the methods:
jQuery('#btn').click(function(e){
if(blah){
_eventHandler(e,this);
}else{
_dosomethingElse(e,this);
}
});
and access them in function:
function _dosomethingElse(event,element)
{
$(element).text("Else called");
}
function _eventHandler(event,element)
{
$(element).text("Event Called");
}
Note: By this way now _eventHandler cannot be used as direct event handler for button click,because it is not now a direct event handler as you were doing preciously this way jQuery('#btn').click(_eventHandler); but now it is different.
Just to clarify to the answer already given, "this" keyword always refers to the object that the function or method is operating off of. So in your function '_eventHandler' this was refering to the '_eventHandler' function. Jquery passes the 'selector' object to each of it methods so you could make event handler and extenstion on jQuery prototype. like this...(by the way Jquery.fn = jQuery.prototype
jQuery.fn._eventHandler= function () {
jQuery(this).text('Clicked');
}
... and call is like
jQuery('.yourSelector').click(function() {
jQuery(this)._eventHandler();
});
...and jquery would pass the yourSelecotr as 'this'
You can simply try it out:
function fn(ev) {
console.log('fn ' + this);
}
$('button').click(function (ev) {
function nested(ev) {
console.log('nested ' + this);
}
console.log('click ' + this);
fn(ev);
nested(ev);
fn.call(this, ev);
});
Output:
"click [object HTMLButtonElement]"
"fn [object Window]"
"nested [object Window]"
"fn [object HTMLButtonElement]"
this context is set to window when you call a function. You can use the method Function.prototype.call(thisContext [, arg1 ...]) to set the this context explicitly.
I'm using jQuery and I have a function that serves as an event callback, and so in that function "this" represents the object that that captured the event. However, there's an instance where I want to call the function explicitly from another function - how do I set what "this" will equal within the function in this case?
For example:
function handleEvent(event) {
$(this).removeClass("sad").addClass("happy");
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
handleEvent(e); // in this case, "this" will be the window object
// but I'd like to set it to be, say, the input in question
}
}
Use apply call.
handleEvent.call(this, e);
Just parameterize the function you're interested in:
function doStuff(el) {
$(el).removeClass("sad").addClass("happy");
}
function handleEvent(event) {
doStuff(this);
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
doStuff(this);
}
}
Use
e.target
I'd advice you re-factoring your function as a jQuery plugin.
But here's a quick Fix:
handleEvent.apply(this,e) //transfers this from one scope, to another
If you're simply looking to call a single event handler as if it were being triggered normally, apply/call will work fine. However, depending on your needs, it may be more robust to use the zero-argument version of jQuery's click() function, which will trigger all click handlers for that element:
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
$(this).click(); // simulate a click
}
}