While creating an array of table data, I'm trying to pass the current ID of an image into a function using an onClick event. What am I doing wrong here? I had the impression a simple solution such as this.id or an event handler would function correctly. Any ideas? Thank you!
function deleteRecord(event)
{
alert(event.target.id);
}
let j = 0;
for(let i in dataRes)
{
j++;
arr.push
(
<tr>
<td><div><img id={j} src={"RANDOM IMAGE"} onClick={(event)=>deleteRecord(event)} /><span id={"item"+j}>{DATA}</span></div></td>
<td>{DATA}</td>
<td>{DATA}</td>
</tr>
);
}
You're passing in the onClick event into the function, when all you need to pass is the value of j. However, we want to pass the value of j at the point in the loop, so we need to make a copy of j before passing it in.
So right after j++;, we need to create a new copy let j_copy = j;
Then your onClick function should be:
onClick={()=>deleteRecord(j_copy)}
and your deleteRecord function:
function deleteRecord(index)
{
alert(index); // alerts the value of j_copy
}
This hard-codes the value of j each time the loop runs. Note that each time the loop runs, a new HTML fragment with a different onClick handler gets generated with that hard-coded value. So the first time, it's equal to onClick={()=>deleteRecord(1)}, the second time it's onClick={()=>deleteRecord(2)}, and so on.
Related
So basically in the bellow code I want to access the image which is related to the index of the array. Now on the console.log(i), I get "1" as there are two elements in the array.
However, when I click the "array" I get "../[object%20PointerEvent]1.png". This causes an error as the file name is 1.png not the above.
Does anyone know how I can remove the [object%20PointerEvent] so I just have the "../1.png"?
Thank you
for(let i = 0; i < array.length; i++) {
console.log(i);
array[i].addEventListener("click", function nextImage(i) {
image.src = i +".png";
});
}
You have two different variables named i.
The one defined in the for loop that you want
The parameter in your callback function which is passed the Event object that you get
Rename the second one so you stop shadowing the first one. Traditional names are e or event but since you aren't using it, you could just remove it.
Using a tool like eslint with the no-shadow rule could have caught this error for you.
The value passed into the object will automatically be the event and not the value from the array. A better way of doing this is:
array[i].addEventListener("click", function nextImage(a){return (event)=>{
image.src = a +".png"}
}(i)
);
My file works just fine in the first round of loop when i try to rerun the function again. It shows the previous value of the previous loop when i try to use the value to match and after which it shows the correct value. If i run the function again and again, it keeps holding on to the value of the previous generated random value.
for (var i=0; i<9; i++)
{
var ranD = Math.floor(Math.random()*33);
if (mathStar.indexOf(ranD)== -1) {
mathStar.push(ranD);
item[i].innerHTML = mathStar[i];
}
else {
i--;
}
itemVal[i].value = mathStar[i];
}
Substitute using const and let for var within for loop to avoid creating global variables and --i could have unexpected results within the code where i++ is also used in the foor loop.
Is this the first occurrence of "mathStar"?
If this is the first place you're using mathStar, it means it gets created globally and that usually leads to confusion. In this case, take a look at this.
Looking at just this, it seems that you are not resetting your "mathStar" value. This way, any time you run this loop for the nth time, the values you have added to "mathStar" using mathStar.push(...) also occur in the list of values.
This feels like a very basic question, but I can't seem to find an answer t it. I have an array of clickable svg rects that have id's "texture-1", "texture-2" etc. The textureInput array holds the getElementById's for those rects, that call a changeTexture() function on click. I want "1" to be passed into the changeTexture() function when "texture-1" is clicked on etc.
Manually assigning these values works: e.g.
textureInput[0].addEventListener('click', function(){changeTexture("0")}, false);
textureInput[1].addEventListener('click', function(){changeTexture("1")}, false);
But doing the same thing in a loop does not:
for (var i=0; i<maxTextures; i++){
textureInput[i].addEventListener('click', function(){changeTexture(i)}
};
Is it passing in the then current value of "i" at event time - which is undefined outside the loop?
You need to create a closure so that a new copy of the i variable is made, otherwise it will use the one that belongs to the for loop. Try this:
for (var i=0; i<maxTextures; i++){
textureInput[i].addEventListener('click', (function(i) {
return function () {
changeTexture(i);
};
})(i));
};
Use a closure. One simple way is wrap an IIFE around the code within the loop
for (var i=0; i<maxTextures; i++){
(function(i){
textureInput[i].addEventListener('click', function(){changeTexture(i);}
})(i);
};
my problem is that I need handle multiple events for rectangle. That sound simple,
for example this works
node.click(function(e){
click(); // this is function defined in same scope, it works ok
});
node.mouseout(function(e){
mouseout();
});
But, I want to automatize this, so it should looks like this:
var events = new Array("click", "mouseout");
for(var i in events){
node[events[i]](function(e){
events[i](); /*THIS is problem, no matter if it is click or mouseout
this always fires function with same name as last item
in events array (in this case mouseout)
*/
}
}
Do you have any idea why a how I should solve it?
Your handlers created in a loop are sharing a variable. By the time they are called, the variable is the last value in the loop.
You have to use a technique I call "freezing your closures" so that each handler gets a separate copy of the shared variable. In your case, the shared variable that changes is i
Your other problem is that you want to call your functions "click/mouseout" from a string, so you have to get a handle to the function, right now your code is attempting to call "hello"() which does not work
Your last problems (but not a bug yet) are that you shouldn't use the Array constructor and you shouldn't use a for in loop to iterate over arrays.
function createHandler(eventName) {
return function(e) {
window[eventName]();
}
}
var events = ["click", "mouseout"];
for(var i=0; i < events.length; i++){
node[events[i]](createHandler(events[i]));
}
The above example is easier to comprehend but you could use self invoking anonymous functions to do the same thing
var events = ["click", "mouseout"];
for(var i=0; i < events.length; i++){
node[events[i]]((function(eventName){
return function(e) {
window[eventName]();
};
})(events[i]));
}
Let me describe my scenario before I say my question:
Let counter be defined already as a number starting from 0.
I have 2 a tags: let them be a1 and a2
I first dynamically added a1 into my html and then used this:
jQuery("a.adder").click(function(){adder(this, counter)});
then I did counter++
then I dynamically added a2 into my html and then used this again on both my a tags
jQuery("a.adder").click(function(){adder(this, counter)});
then I did counter++
also, in my adder(param1, param2) , all I do is alert(counter)
Okay here's my question: After doing all that, when I clicked on a1 which has 2 handlers, the alert output is 2 (it alerts twice for each handler) and for a2, the alert is also 2 when clicked. Why is this happening?
The reason it returns 2 for both is that your anonymous functions are creating a closure over the counter variable. What this means is that those methods don't just have the current value of counter when you bind them, they have a reference to the variable.
Any changes in that variable later on will be reflected in the captured variable.
You can prevent this by creating a new variable for the second binding:
var counter = 0;
function adder(e, counter) {
alert(counter);
}
jQuery("<a class='adder'>a1</a><br />')").appendTo("body");
jQuery("a.adder").click(function(){adder(this, counter)});
counter++;
var newCounter = counter;
jQuery("<a class='adder'>a2</a>')").appendTo("body");
jQuery("a.adder").click(function(){adder(this, c)});
counter++;
Here is created a new counter variable called newCounter which is capture by the second event handler.
you made two click events, and your click events return the current value of 'counter'