To modify this keyword in Javascript - javascript

How should I replace the this with the original calling object? I understand this is a simplified way to present it but I was trying to understand the object that the this was referencing to.
for(var i=0; i<list.length; i++){
list[i].addEventListener("click", liClick);
}
function liClick(){
this.classList.toggle("done");
}
My understanding is that this is referring to the list[i] which has been clicked, but when I tried with
function liClick(){
list[i].classList.toggle("done");
}
it was wrong, how should I modify it? Thanks.

You can do something like this:
for (var i = 0; i < list.length; i++) {
list[i].addEventListener("click", liClick);
}
function liClick(e) {
e.target.classList.toggle("done");
}

this keyword doesn't refer to list item.
You should pass list[i] to function
the function listClick receive event and you can directly access e.target or make callback function and pass item
for(var i=0; i<list.length; i++){
list[i].addEventListener("click", () => liClick(list[i]) );
}
const liClick = (listItem) => {
listItem.classList.toggle("done");
}

Related

How to properly pass argument in loop to multiple event handlers? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript closure inside loops - simple practical example
I add event handlers to multiple hrefs on my website with JS like this:
function addButtonListener(){
var buttons = document.getElementsByClassName("selLink");
for (var i = 0; i < buttons.length; i++)
{
button.addEventListener('click',function() { addTosel(i); },true);
}
}
}
But unfortunately to addTosel is passed the last i not the i from the loop. How to pass i accordingly to the object being processed in this moment?
You need to create a closure:
function addButtonListener(){
var buttons = document.getElementsByClassName("selLink");
for (var i = 0; i < buttons.length; i++) {
button.addEventListener('click', function(index) {
return function () {
addTosel(index);
};
}(i), true);
}
}
This way the scope of the handler is bound to the proper context of i.
See this article for more information on this subject.
You need to bind the i variable to the function when its declared. like so
for (var i = 0; i < buttons.length; i++) {
button.addEventListener('click',(function() { addTosel(this); }).bind(i) ,true);
}
Note: I just wrote the code from memory so it may not be perfect, but it is the sulution you're needing, for reference as to the proper way, ie with cross browser shims etc look at:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
If you're going to take the .bind approach, do it like this.
for (var i = 0; i < buttons.length; i++) {
button.addEventListener('click', addTosel.bind(null, i), true);
}
This makes a new function with null bound as the this value since your function doesn't seem to need it, and the current i bound as the first argument.
Or make your own binder function
var _slice = Array.prototype.slice;
function _binder(func, ctx /*, arg1, argn */) {
var bound_args = _slice.call(arguments, 2);
return function() {
return func.apply(ctx, bound_args.concat(_slice.call(arguments)));
}
}
And then do this.
for (var i = 0; i < buttons.length; i++) {
button.addEventListener('click', _binder(addTosel, null, i), true);
}

Closure trouble: passing "event" to named function

I'm debugging a bit of Javascript that was suffering from a little closure trouble - but don't seem to be able to pass the "event" argument into the function.
Here's the problem (in shorthand):
// let's say links.length == 3
for(var i = 0; i < links.length; i++){
links[i].onclick = function(e){
alert(i); //closure! all links alert "3"
// do something with "e"
}
}
Here's my solution
//workaround
// define function outside of loop
function outer(e,i){
return function(){
alert(i); //closure! all links alert "3"
// do something with "e"
}
}
for(var i = 0; i < links.length; i++){
links[i].onclick = outer(e,i); //uh oh! e = undefined???
}
In my workaround, I've defined a function outside the loop to prevent closure - but I am unable to pass the "e" argument to it. Can someone point me in the right direction?
Define it in the returned function.
function outer(i){
// ------------v-- event object is passed when this function is invoked
return function( e ){
alert(i);
}
}
for(var i = 0; i < links.length; i++){
links[i].onclick = outer(i);
}
The event object gets passed when the event occurs, so it needs to be defined as a parameter to the function that is ultimately assigned as the handler (the function you're returning from outer()).

Passing a function into another function

I have a function that is similar to this:
function foo(array1, fun) {
var n;
n = a.length;
var i;
for (i=0; i<=n; i++) {
fun(a[i]);
}
}
Now I want to create a function called mult(x) that I will pass into foo when I call it. My question is what do I put in the parameters of my mult function when I want to call:
foo(some_array, mult(x));
Just pass in a reference to it (its name only)...
foo(some_array, mult);
Alternatively, pass in an anonymous function...
foo(some_array, function() { ... });
The first argument of this function you pass in with will be set to a[i] like in the body on your function.
Rewritten to showcase how you call a function in JS
function mult(x){
//do stuff to x
}
function foo(array1, fun){
var n = array1.length;
var i;
for (i=0; i<=n; i++) {
mult(array1[i]);
}
}

Jquery Scope Issue

I can't figure out this scope issue:
var menuLinks = new Array("about.php", "contact.php");
function setClickListeners()
{
for(var i=0; i<menuItems.length; i++)
{
$("#" + menuItems[i]).click( function () {
window.alert(menuLinks[i]);
});
}
}
Notes: menuItems and menuLink is the same length. This code is stripped down to make understanding it easier.
The outcome of this code when an item is clicked is an alert "undefined". It should be the data from menuLinks.
Help!!!!
Frankie
for (var i=0; i < menuItems.length; i++) {
(function(i) {
$("#"+menuItems[i]).click(function() {
alert(menuLinks[i]);
});
}(i));
}
You need to make the current value of i local to your anonymous function in .click.
JavaScript only has function scope. So if you don't make i local then whenever you press click the value of i is the current value which in this case is menuItems.length - 1.
What your doing above is creating a new functional scope and passing the value of i into it so that the current value of i stays constant in that function scope. That way your click function picks up the constant value of i from the closure.
jslint
Let's over complicate the code and satisfy jslint.
var wrapper = function(i) {
$("#"+menuItems[i]).click(function() {
alert(menuLinks[i]);
});
};
for (var i=0; i < menuItems.length; i++) {
wrapper(i);
}
A cleaner code:
var menuLinks = new Array("about.php", "contact.php");
function setClickListeners()
{
$.each(menuLinks, function(i, element)
{
$("#" + menuItems[i]).click( function (e) {
alert(menuItems[i]);
e.preventDefault();
});
}
}

Arguments to JavaScript Anonymous Function

for (var i = 0; i < somearray.length; i++)
{
myclass.foo({'arg1':somearray[i][0]}, function()
{
console.log(somearray[i][0]);
});
}
How do I pass somearray or one of its indexes into the anonymous function ?
somearray is already in the global scope, but I still get somearray[i] is undefined
The i in the anonymous function captures the variable i, not its value. By the end of the loop, i is equal to somearray.length, so when you invoke the function it tries to access an non-existing element array.
You can fix this by making a function-constructing function that captures the variable's value:
function makeFunc(j) { return function() { console.log(somearray[j][0]); } }
for (var i = 0; i < somearray.length; i++)
{
myclass.foo({'arg1':somearray[i][0]}, makeFunc(i));
}
makeFunc's argument could have been named i, but I called it j to show that it's a different variable than the one used in the loop.
How about a closure:
for (var i = 0; i < somearray.length; i++) {
var val = somearray[i][0];
myclass.foo({'arg1': val}, function(v) {
return function() {console.log(v) };
}(val) );
}
for (var i = 0; i < somearray.length; i++)
{
myclass.foo({'arg1':somearray[i][0]}, function(somearray)
{
console.log(somearray[i][0]);
});
}
And then in method foo call anonymous function with param.
You can pass variables values to annoymous function by using callback,
something like
myclass.foo(function(variable){
return function(){
console.log(variable);
}
})(variableValue);
);
check this post: https://shahpritesh.wordpress.com/2013/09/06/javascript-function-in-loop-passing-dynamic-variable-value/
All the functions/methods can be used as callbacks only. When you call the callback function you pass variables to it.
var myclass = {
foo: function(params, callback){
// do some stuff
callback(variable1, variable1, variableN);
}
}

Categories

Resources