Cannot get _.debounce() to work - javascript

I am having trouble trying to get underscore.debounce() to work. I am attaching a keydown event listener on an input field. I will perform some actions, then call debounce() which is not being called. I am wondering why it is not working?
I have provided two samples. The first one where I have not attached _.debounce() as inline is not working. The second one where I have attached _.debounce() as inline is working. I do not understand why the non-inline solution is working?
// This example does not ever call _.debounce()
$('input').on('keydown', onKeyDown);
function onKeyDown() {
console.log('performing some actions...');
_.debounce(function() {
console.log('debouncing'); // never called
}, 500);
}
// This example does call _.debounce()
$('input').on('keydown', _.debounce(function() {
console.log('debounce');
}, 500));

Debounce returns a function that will need to be invoked, in this case you are creating a function but never invoking it. Try this:
// This example does not ever call _.debounce()
var debounced = _.debounce(debounceStuff, 500);
$('input').on('keydown', onKeyDown);
function onKeyDown() {
console.log('performing some actions...');
debounced();
}
function debounceStuff() {
console.log('debouncing');
}

Related

Difference between callback functions and event handlers

I started web development recently, and i can't seem to wrap my head around event handlers and callback functions. I understand that events handlers are a type of callback, and they respond to events unlike the more general definition of callbacks that get called by some other code when it finishes running. But, I'm looking for an explanation that 'sticks' with me.
Here's an example
<script>
$(document).ready(function(){
$("button").click(function(){
$("p").hide("slow", function(){
alert("The paragraph is now hidden");
});
});
});
</script>
In this code example, i know that ready and click are both events so $("button").click(function(){ is an event handler for the ready event? and $("p").hide("slow", function(){ is an event handler for the click event? How about hide? is it also an event?
Yes, that's correct (took me a second to realize you were just showing the content of the handlers you were referring to). It's clearer if you don't define the handlers/callbacks inline, and you give them descriptive names:
function readyHandler() {
$("button").click(clickHandler);
}
function clickHandler() {
$("p").hide("slow", hideAnimationCompleteCallback);
}
function hideAnimationCompleteCallback() {
alert("The paragraph is now hidden");
}
$(document).ready(readyHandler);
Note that the code above is slightly different from your original, which looks more like this:
function readyHandler() {
function clickHandler() {
function hideAnimationCompleteCallback() {
alert("The paragraph is now hidden");
}
$("p").hide("slow", hideAnimationCompleteCallback);
}
$("button").click(clickHandler);
}
$(document).ready(readyHandler);
...but since none of the handlers/callbacks was relying on the fact it was created inside a handler/callback, it seemed clearer to show them completely independently. But it would matter if they were using something that's only in-scope within the handler they were created in.
Callback functions are what you described. Functions that are passed as parameters to another function and then later "called back".
Example:
file.read(fileName, function (err, data) {
// once file reading has finished, this function body is called,
// so this anonymous function is the callback
});
Event handlers are functions that gets triggered when a specific event occurs. It can be used for synthetic events, websocket events, and more. And its usual syntax is using callbacks.
Examples:
eventBus.on('new_message_arrived', function (err, data) {
// when 'new_message_arrived' event happens, this callback will be called
});
button.click((event) => {
// when button gets clicked, this callback (now used arrow function notaion)
// will be called with the details of the UI event
});

is this a valid way to define an explicit function inside addEventListener?

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>

Passing function to .on() in plain object

I want to call a custom function on mouse enter.
My current code looks like this:
var myFunction = function(element)
{
//do something with element
}
$( selector ).on({
mouseenter: myFunction($(this)),
mouseleave: myFunction($(this))
}, ' selector ');
My problem is that it seems like myFunction() isn't even called. Does this even work or did I mess up something else?
You aren't passing a function. You are calling the function immediately and passing its return value.
Since you want to call the function, with an argument, and the value of that argument isn't determined until the event fires, you need to create a new function.
function use_myFunction_as_event_handler(event) {
myFunction($(this));
}
$('selector').on({
mouseenter: use_myFunction_as_event_handler,
mouseleave: use_myFunction_as_event_handler
}, 'selector');
You are misunderstanding how functions work in javascript. Here's a simple way to make mouseenter call a function.
$(selector).on({
mouseenter: function(event) {
console.log(event);
}
});
This makes sense. When the mouseenter event gets called, the function executes. Great.
Your problem is that this code:
var functionToCall = function(event) {
console.log(event);
}
$(selector).on({
mouseenter: functionToCall(event);
});
does not actually do the same thing as the previous example.
When you put brackets after a function name, you are calling the function. What mouseenter wants is a function reference - javascript will call the function reference you give it for you every time the event occurs.
What we assigned mouseenter to in the first example was an anonymous function reference - we didn't actually call the function we created. Javascript was doing that for us. In the second example, we called the function, so mouseenter was actually set to the return value of the function, not to the function itself.
To fix this, you just need to pass a function reference to the event instead of calling the function. Note, you can't directly pass parameters this way (it's not impossible, but you shouldn't need to), but $(this) will still be the same.
var myFunction = function() {
var element = $(this);
// code...
}
$(selector).on({
mouseenter: myFunction,
mouseleave: myFunction
});
You should call the function as
var myFunction = function(element)
{
//do something with element
}
$('selector').on({
mouseenter: function(){
myFunction($(this));
},
mouseleave: function(){
myFunction($(this));
}
}, 'selector');
Since you want to pass the argument in myFunction, you have do define it like above

Javascript : Replace Event Listener

I am listening to an event and want to call different methods. For example, I am listening to animation end event and the code is something like this:
this.inAnimationCallback = function() {
console.log('In');
_this.elem.className = _this.settings.className;
};
this.outAnimationCallback = function() {
console.log('Out');
_this.elem.parentNode.removeChild(_this.elem);
};
this.elem.addEventListener(animationEvent, this.inAnimationCallback);
setTimeout(function() {
_this.elem.addEventListener(animationEvent, _this.outAnimationCallback);
// Call some animation here.
}, 3000);
What happens here is that instead of replacing the method attached to the event, JS adds the method and when animation ends, both methods are called. Console looks like this:
(2) In
Out
I'm writing this answer for those like me, who is just started learning JS. And this thread came up first in google to "js replace event listener"..
Although, I am not disagreeing with the answers to use removeEventListener(), but mozilla warns that this function is not always successful. So use it with care. not willing to go that road i have found two other ways to do it.
Use something like GlobalEventHandlers which is simple as target.onclick = functionRef;. Mozilla even warns:
Only one onclick handler can be assigned to an object at a time.
Within listener function add external function call to action function, and then replace reference to another external action function. For example this code will call firstAction(), then seconAction(), then first again...:
const buttonOne = document.getElementById('buttonOne');
buttonOne.addEventListener('click', listenerFunction);
let doAction = firstAction; //assigning doAction to firstAction
function listenerFunction() {
doAction(); //external function call
}
function firstAction() {
doAction = secondAction; //assigning doAction to secondAction
console.log('first action clicked');
}
function secondAction() {
doAction = firstAction; //assigning doAction to firstAction
console.log('second action clicked');
}
<button type="button" id="buttonOne" name="button">button1</button>
I wrote this answer to broaden solution scope: would have saved at least 6 hours of my time. If I had this in the first place...
You can just remove the event listener before adding the new one :
setTimeout(function() {
_this.elem.removeEventListener(animationEvent, _this.inAnimationCallback);
_this.elem.addEventListener(animationEvent, _this.outAnimationCallback);
// Call some animation here.
}, 3000);

How can I add an event for a one time click to a function?

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');
});

Categories