first time using stackoverflow. :)
I am a beginner in JS trying to add values to a list of variables that may change based on the number of passengers variable. (ie. if numRiders = 4 I need to assign values to passenger1Name, passenger2Name, passenger3Name, passenger4Name)
I am trying to use eval inside a loop to do it:
for(i = 0; i<=numRiders; i++) {
j = i+1
var l ='var '
var k = 'passenger'
let nameJ = ride[i].passengerDetails.first + ' ' + ride[i].passengerDetails.last;
console.log (nameJ)
eval(l+k+j+ 'Name' + '= ' + nameJ + ';')
console.log(passenger1Name)
I am getting this output right after the nameJ console.log
VM321:1 Uncaught SyntaxError: Unexpected identifier
at pageLoad
Anyone know how can I solve this or approach this differently? Unfortunately, I can't change the variables names (e.g. passengerXName) to one that would make it easier to assign dynamic variables.
Thank you
nameJ appears to be a string. So you need to put quotes around it.
eval(l+k+j+ 'Name' + '= "' + nameJ + '";')
But as others stated in the comments, defining variables dynamically like this is almost never what you really want.
I have since 1996 or so RARELY seen any reason for eval
This is recommended
const rides = [
{ passengerDetails: {first:"Fred",last:"Flinstone"}},
{ passengerDetails: {first:"Wilma",last:"Flinstone"}}
]
const names = rides.map(ride => `${ride.passengerDetails.first} ${ride.passengerDetails.last}`)
console.log(names)
or even
const rides = [
{ passengerDetails: {first:"Fred",last:"Flinstone"}},
{ passengerDetails: {first:"Wilma",last:"Flinstone"}}
]
const names = rides.reduce((acc,ride,i) => {
acc[`passenger${i+1}name`] = `${ride.passengerDetails.first} ${ride.passengerDetails.last}`
return acc;
},{})
console.log(names)
If you MUST, try this assuming you have a window scope to add it to
const rides = [
{ passengerDetails: {first:"Fred",last:"Flinstone"}},
{ passengerDetails: {first:"Wilma",last:"Flinstone"}}
]
rides.forEach((ride,i) => {
let nameJ = `${ride.passengerDetails.first} ${ride.passengerDetails.last}`;
window[`passenger${i+1}Name`]=nameJ;
})
console.log(passenger1Name)
The option from #ZacAnger
var names = {};
for(i = 0; i<=numRiders; i++) {
j = i+1
let nameJ = ride[i].passengerDetails.first + ' ' + ride[i].passengerDetails.last;
names['passenger'+ j+ 'Name'] = nameJ;
}
Related
I wanted to get the value of an HTML input by using the dollar ($) sign, since I have to make a String the only way I can think of is using the eval() function, but since it is not recommended I wanted to know which alternative could I use.
Basically here ${player} can be "player1" or "player2":
eval(`${player}NameInput`)
So that it access one or the other of this input elements:
const player1NameInput = document.getElementById("name1")
const player2NameInput = document.getElementById("name2")
Here is the code with more context:
const player1NameInput = document.getElementById("name1")
const player2NameInput = document.getElementById("name2")
const player = event.target.id.slice(7,14) // Can be "player1" or "player2"
let name = document.getElementById(`${player}-name`) // A label
name.textContent = eval(`${player}NameInput`).value + ": "
eval(`${player}NameInput`).value = ""
I've tried the function approach and the window[variable] approach but I couldn't make them work, I also have the feeling that there must be a simpler approach.
In the function approach I did:
Function('"use strict"; return ' + `${player}NameInput`)()
Which gives me this error:
Uncaught ReferenceError: player1NameInput is not defined
at eval (eval at changeName (script.js:158:21), <anonymous>:3:15)
at HTMLButtonElement.changeName (script.js:158:77)
Thanks!
If you really need to use string interpolation to get the value, you can put the values in an object:
const players =
{
player1NameInput: document.getElementById("name1"),
player2NameInput: document.getElementById("name2")
};
const player = event.target.id.slice(7,14); // Can be "player1" or "player2"
let name = document.getElementById(`${player}-name`); // A label
name.textContent = players[`${player}NameInput`].value + ": ";
players[`${player}NameInput`].value = '';
Use an object to store them by name, instead of multiple variables.
const nameInputs = {
player1: document.getElementById("name1"),
player2: document.getElementById("name2"),
}
const nameLabels = {
player1: document.getElementById("player1-name"),
player2: document.getElementById("player2-name"),
};
const player = event.target.id.slice(7,14) // Can be "player1" or "player2";
nameLabels[player].textContent = nameInputs[player].value + ": ";
nameInputs[player].value = "";
Even easier to access (in general) might be an array, with index 0 for player 1 and index 1 for player 2. This will make for simpler code when iterating all elements or toggling between them.
I am trying to loop an array using for loop. As soon as the variable goes inside the firebase query, only the last value is displayed. Any idea why this is happening?
const handleClose = () => {
var tpList = TP;
for (var v in tpList) {
var tp = tpList[v];
console.log(tp);
Firebase.database().ref("Student").child(tp + "/Name/").once('value').then((res) => {
console.log("Name of " + tp + " is " + res.val());
})
}
The first console log works perfeclty fine, showing the correct values from index 0-5. However, the second console log shows only the index value of 5. Any suggestions what could be wrong here?
As mentioned in the comment, you'd use let instead of var in the loop:
const handleClose = () => {
var tpList = TP;
for (let v in tpList) { // Use let here
let tp = tpList[v]; // (optional) Also here to keep the scope inside the loop
console.log(tp);
Firebase.database().ref("Student").child(tp + "/Name/").once('value').then((res) => {
console.log("Name of " + tp + " is " + res.val());
})
}
The reasons for this is that in ES6 when using let in a loop, the declared variable will get a new binding for each iteration of the loop, so the closure will correctly capture each value of v, instead of capturing only the last one as it happens when using var.
I have a problem to manipulate checkbox values. The ‘change’ event on checkboxes returns an object, in my case:
{"val1":"member","val2":"book","val3":"journal","val4":"new_member","val5":"cds"}
The above object needed to be transformed in order the search engine to consume it like:
{ member,book,journal,new_member,cds}
I have done that with the below code block:
var formcheckbox = this.getFormcheckbox();
formcheckbox.on('change', function(checkbox, value){
var arr=[];
for (var i in value) {
arr.push(value[i])
};
var wrd = new Array(arr);
var joinwrd = wrd.join(",");
var filter = '{' + joinwrd + '}';
//console.log(filter);
//Ext.Msg.alert('Output', '{' + joinwrd + '}');
});
The problem is that I want to the “change” event’s output (“var filter” that is producing the: { member,book,journal,new_member,cds}) to use it elsewhere. I tried to make the whole event a variable (var output = “the change event”) but it doesn’t work.
Maybe it is a silly question but I am a newbie and I need a little help.
Thank you in advance,
Tom
Just pass filter to the function that will use it. You'd have to call it from inside the change handler anyway if you wanted something to happen:
formcheckbox.on('change', function(cb, value){
//...
var filter = "{" + arr.join(",") + "}";
useFilter(filter);
});
function useFilter(filter){
// use the `filter` var here
}
You could make filter a global variable and use it where ever you need it.
// global variable for the search filter
var filter = null;
var formcheckbox = this.getFormcheckbox();
formcheckbox.on('change', function(checkbox, value){
var arr = [],
i,
max;
// the order of the keys isn't guaranteed to be the same in a for(... in ...) loop
// if the order matters (as it looks like) better get them one by one by there names
for (i = 0, max = 5; i <= max; i++) {
arr.push(value["val" + i]);
}
// save the value in a global variable
filter = "{" + arr.join(",") + "}";
console.log(filter);
});
I'm currently using javascript eval() to check and create a multidimensional object that I have no idea of the depth.
Basically, I want to know if there's any way to create this multi-depth object. The object can be as deep as result['one']['two']['three']['four']['five']['six']['seven']. I know there are cases where using eval() is perfectly fine, but I'm also worried about performance. I thought about referencing each depth to a new variable, but I don't know how to do pointers in Javascript
create = function(fields, create_array){
var field;
for (j = 0; j < len; j++){
field = fields.slice(0, j).join('');
if (field){
// is there any way to do this without eval?
eval('if (typeof result' + field + ' == "undefined" || !result' + field + ') result' + field + ' = ' + (create_array?'[]':'{}') + ';');
}
}
}
How about
var deep = { one: { two: { three: { four: { five: { six: { seven: 'peek-a-boo!' }}}}}}};
I don't see what "eval()" has to do with this at all; there's no reason to "initialize" such an object. Just create them.
If you wanted to write a function with an API like you've got (for reasons I don't understand), you could do this:
function create(fields, create_array) {
var rv = create_array ? [] : {}, o = rv;
for (var i = 0; i < fields.length; ++i) {
o = o[fields[i]] = create_array ? [] : {};
}
return rv;
}
There doesn't seem to be any point to the "create_array" flag, since you're presumably always using strings for keys.
Never mind, found my way in. I used a recursive function to ensure that the object was created properly.
create = function(create_array, res, path){
var field = fields.shift();
if (field){
if (typeof res[field] == "undefined" || !res[field]) res[field] = (create_array?[]:{});
path.push('["' + field + '"]');
create(create_array, res[field], path);
}
}
var result = {}, strpath = [], fields[];
create(true, result, strpath);
eval('result' + strpath.join('') + ' = value;');
being variable "field" a variable outside the function, that contained the levels of the object. doing result["field"]["name"]["first"] = value without the ["field"] or ["name"] field existing or defined as an object, would throw an error and stop execution, that's why I'm pre-creating the object variable, either as an array or object.
I couldn't find another option for the second eval() though. There's no way to provide a way to access multiple properties on an object without knowing the depth.
I think it's fairly clear what I want to do here:
var viewnames = {};
viewnames['region-a'] = "Region A";
viewnames['region-b'] = "Region B, partial";
viewnames['region-c'] = "Region C";
function loadView(view_name) {
alert('view_name: ' + view_name);
alert('viewname: ' + viewnames.view_name);
document.getElementById("viewtitle").innerText = view_name;
}
But if I call this with view_name as region-a the alert says viewnames.view_name is undefined. What is the problem?
You must use viewnames[view_name] inside your function loadView
You need to index it by name, e.g. viewnames[view_name]
Access it by associative array index (viewnames[view_name]). Please DO NOT use an eval construct (eval("var tmp = viewnames." + view_name + ";")).