React onClick Events in loops - javascript

Im trying to bind some variables to a onClick event inside a React Component. Im doing this from within a for loop because I need many of them.
My code looks like this:
generateCells(pieData){
var cells = []
for(var j = 0; j < pieData.length; j++){
var imageIndex = pieData[j].image;
var image = [pieData[j].innerIndex, pieData[j].angle];
console.log(image);
var rowLength = pieData.length;
cells.push(<Cell key={imageIndex} onClick={() => this.retake(image, rowLength)} fill={this.state.progressState[imageIndex] ? '#00C49F' : '#FF8042'}/>)
}
return cells;
}
But my image variable in the onClick event is always from the last iteration of the loop. How is this possible?
Thanks for any advice!

This is because you're using var and it's creating a variable scoped into you're generateCells() function. Try with let to see the difference (the variable scope will be the for loop)
I did a Codepen some time ago to view the difference between them, this may help you: https://codepen.io/ArthyFiciel/pen/rxKeQR

Change var to let in for loop. let create new binding and let creates a variable declaration for each loop which is a block-level declaration. while var scoped to the global scope so by the time you click var value is attached to the global scope and displaying last value:
for(let j = 0; j < pieData.length; j++){
var imageIndex = pieData[j].image;
var image = [pieData[j].innerIndex, pieData[j].angle];
console.log(image);
var rowLength = pieData.length;
cells.push(<Cell key={imageIndex} onClick={() => this.retake(image, rowLength)} fill={this.state.progressState[imageIndex] ? '#00C49F' : '#FF8042'}/>)
}
return cells;
Demo : https://stackblitz.com/edit/react-geu71r

Change var to let infor loop, this should help

Related

Passing variables through addEventListener

I am trying to add event to all inputs, get the value (number) from those and insertHtml them into span elements.
This is my javascript code. I have no idea how to pass the variables.
var input_selector = document.querySelectorAll('.coins_n'); // input number elements
var price_selector = document.querySelectorAll('.price'); // span elements
for(var i = 0; i <= input_selector.length; i++) {
var input = input_selector[i];
var price = price_selector[i];
input.addEventListener('input', function(){
console.log(price); // not working
console.log(input); // not working
price.innerHTML = input.value; // not working
})
}
The problem here has to do with scoping of your variables. var is a weird one, whose scope isn't really limited to the block, but to the containing function. The following two are (essentially) the same:
var input;
var i = 0;
for(; i < input_selector.length; i++) input = input_selector[i];
and
for(var i = 0; i < input_selector.length; i++) var input = input_selector[i];
both create a variable named input in global scope, and then update that variable. That means that any functions that wants to read input later will just read the last version of input, and not the version at the time you defined the handler you would trigger later.
let, however, is block scoped, and your for loop is a block. So defining let input inside the for loop will mean that input is defined uniquely for every iteration of the loop, since every time the block gets executed a new scope is created for everything in there.
The same is true for var i = 0 in your for loop - any handler that calls it later will just log the last global value of i, but if you use let, that's not the case and every iteration of the loop has its own i. So your code could simply be reduced to this:
const input_selector = document.querySelectorAll('.coins_n');
const price_selector = document.querySelectorAll('.price');
for( let i = 0; i < input_selector.length; i++ ){
input_selector[i].addEventListener('input', event => {
price_selector[i].innerHTML = event.target.value;
});
}
This is pretty complex to explain once you start typing it out, so better read what other have already written at something like MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Ok. I've managed it by using let.
var input_selector = document.querySelectorAll('.coins_n');
var price_selector = document.querySelectorAll('.price');
for(var i = 0; i < input_selector.length; i++) {
let input = input_selector[i];
let price = price_selector[i];
input_selector[i].addEventListener('input', function(){
price.innerHTML = this.value;
})
}

How to attach a specific variable value from a loop iterating to a one dynamically created element

i am doing a bucle for to get the keys from local storage archives and i want to attach that keys to dynamically created elements the way that when i click over the new created element (who recives the name of the storage file) it will alert the content. This is what i have, the problem is in archivo[ keys[i] ].
function local(){
archivo = {};
keys = Object.keys(localStorage);
i = 0; var key;
for (i = 0; key = keys[i] ; i++) {
var compra_recuperada = document.createElement('ons-list-item');
compra_recuperada.innerHTML = keys[i];
document.getElementById('compra').appendChild(compra_recuperada);
archivo[ keys[i] ] = localStorage.getItem( keys[i] );
compra_recuperada.addEventListener('click', function(){ alert(archivo[ keys[i] ])
})}};
Remove the declaration of variable i outside of the loop and change for (i = 0; key = keys[i] ; i++) to for (let i = 0; key = keys[i]; i++) should work for your case.
In the previous version, each element shares the same variable i. By the time you see the alert, it is already changed to the last value. The second version will create a new variable for each loop iteration thanks to the ES6 let keyword.

How to create a variable by setting a custom identifier as variable name

This looks crazy but it was a much-needed solution for my application to solve the problem of dynamic initialization...
when I inject the services dynamically I would like it to be identified by my own variable which matches the service.
Here is what >I want.
$rootScope.arr = ['MasterLookupService', 'PrinterService'];
for (i = 0; i < arr.length; i++) {
var arr[i] = $injector.get(arr[i]);
}
// it will end up something like this
var MasterLookupService = $injector.get('MasterLookupService');
I tried but none helped
// $rootScope.customObj = {
// MasterLookUpService: $injector.get('MasterLookupService'),
// PrinterService: $injector.get('PrinterService')
// }
I'm not sure about Jquery but this might be what I understand you need.
var arr = ['MasterLookupService', 'PrinterService'];
for(var i =0 ;i < arr.length; i++){
var varname = arr[i];
window[varname] = 'value '+i;
}
alert(MasterLookupService);
window object represents a window containing a DOM document. You may use other object depending upon your environment.

Javascript loop push into global array

1.I want to push id[i] into global array.After I pushed then it will be id.length numbers items in each array,but it will be error and says y is not a function.how to solve it?
2.the sendrequest in the bottom will send a xmlhttprequest to server,but I don't understand why it will run first and then the function(parResponse) will be fire after tmpReadRequest.sendReadRequest(); has down.
Thanks a lot
var tes0=new Array();
var tes1=new Array();
var tes2=new Array();
var tes4=new Array();
var tes5=new Array();
function ReadValuePath(id, Variable,id_2) {
var tmpReadCB = function(parResponse)
{
for (var tmpIndex = 0; tmpIndex < parResponse.length; tmpIndex++)
{
var tmpItemValue = parResponse[tmpIndex];//console.log(tmpItemValue);
var tmpValue = (tmpItemValue.mItemValue) ? tmpItemValue.mItemValue : tmpItemValue.mItemResultId;
if(document.getElementById(id[tmpIndex]) != null && document.getElementById(id_2[tmpIndex]).value != 0)
{
document.getElementById(id[tmpIndex]).value = parseFloat(tmpValue).toFixed(2);
}
}
return true;
}
var tmpReadRequest = new OPCReadRequest("DE", tmpReadCB);
for(var z=0;z<5;z++ ){
for(var i = 0; i < id.length; i++)
var y="tes"+z;
y.push(id[i]);
tmpReadRequest.addItem("ab", Variable[i]);
}
}
tmpReadRequest.sendReadRequest();
}
"A variable declared outside a function, becomes GLOBAL.
A global variable has global scope: All scripts and functions on a web page can access it. " # Source
Y is not an array so .push() won't work on it. # Source
To access the global scope through a string literal like you are trying you can use the window object which is the current global scope.
So in your case it would be window[y].push(id[i]);
Another option would be to change you scructure slightly as personally i don't like accessing the window directly.
so you could define your arrays like
var arrays = {
tes0: [],
tes2: [],
tes3: [],
tes4: [],
tes5: [],
}
and access them like:
arrays[y].push(id[i])
EDIT according to comments
So you want to access global variable in a loop. You are half way there. What your doing is building a string y which contains the property name then using that in the square brackets to access that property.
So with the window option that would be:
for(var z=0;z<5;z++ ){
var y="tes"+z;
for(var i = 0; i < id.length; i++)
window[y].push(id[i]);
}
}
or with the second object option
/*
Because arrays is an object we can use Object.keys
This will return an array of the keys in our object which we can loop over to access each one
*/
Object.keys(arrays).forEach(function(key) {
for(var i = 0; i < id.length; i++)
arrays[key].push(id[i]);
}
});
Hope that helps explain

Javascript Dynamic GetElementByID

I would like to use the same function on two different elements without duplicating my code and changing the id. I'd like to pass the ID as a parameter into my function but it's not working.
function getSelected(id){
var selected = new Array();
**var selObj = document.getElementById(id);** //The problem is here
var count = 0;
for (x=0; x<selObj.options.length; x++){
if (selObj.options[x].selected){
selected[count] = selObj.options.value;
count++;
}
}
alert(count)
}
Any ideas?
Looks to me as if the error is somewhere else, specificially in this line:
selected[count] = selObj.options.value;
Shouldn't that be:
selected[count] = selObj.options[x].value;
or (without the need for an extra "count" variable)
selected.push( selObj.options[x].value );
(Furthermore, you're missing a var in front of x = 0, thus making x a global variable.)

Categories

Resources