Is there an easy way to create dynamic variables with Javascript? - javascript

I've built a data-driven google map with different icons that get assigned to the map depending on the type of item located. So if I have 5 types of landmark, and each gets a different icon (store, library, hospital, etc.)-- what I'd like to do is generate the google icon objects dynamically. I was thinking something like this:
types = array('hospital','church','library','store',etc);
var i=0;
while (i<=types.length) {
var landmark + i = new google.maps.Icon();
landmark.image = "icon" + i + ".png";
i++;
}
however, as you've probably guessed, this doesn't work. I also tried using eval, like this:
while (i<=types.length) {
doIcon(i);
i++;
}
function doIcon(i){
eval("var landmark" + i + " = new.google.maps.Icon();");
return eval("landmark" + i);
}
but it didn't work either-- I'd appreciate any pointers on generating javascript variables dynamically. It's got to be pure js, I could do it in PHP but that's not an option here.
Thanks!

It's really easy to do: object["variablename"] = whatever;
So for example you could have an object: var Landmarks = {} and you could add to it like so: Landmarks["landmark" + i] = new google.maps.Icon(); and pass it that way.
If you need these variables to be global (why would you?) you can access the global object directly using window.

If you're going to do it using a declared object such as Landmark["landmark" + i], you really may as well use an index array rather than an associative, it's much easier for iteration. Objects aren't really used with indexed properties because Arrays do a much better job of it:
var myObj = // object version
{
"item0": "blah",
"item1": "blah"
// etc
}
var myArr = // array version
[
"blah",
"blah"
// etc
]
Much more sensible to use the array:
landmarks = []; // new array
types = array('hospital','church','library','store',etc);
var i=0;
while (i<=types.length) {
landmarks.push(new google.maps.Icon());
landmarks[i].image = "icon" + i + ".png";
i++;
}
It makes more sense to do it that way and for...in loops on objects can get a bit messy with prototyped properties being enumerable, etc.
If you're trying to make a variable global, add it to the window object:
var myCustomVar = "landmark" + i;
window[myCustomVar] = new google.maps.Icon();
alert(landmark0);
But this would be polluting the global namespace with many unnecessary variables. So you'd still be better with an array:
window.landmarks = [];
landmarks.push(new google.maps.Icon());
// etc...

Just to answer your question directly (although please note that this is not the solution you want. Check out the other answers. This is just for documentation!), here's a copy-paste from a JavaScript console:
> window["myNamedVar"] = "Hello, World!";
> console.log(myNamedVar);
"Hello, World!"

You'd be better off creating a javascript object which you can use somewhat like an associative array is used in PHP:
var types = ['hospital','church','library','store'];
var landmarks= {};
for (var i in types) {
landmarks[types[i]]= new google.maps.Icon();
landmarks[types[i]].image = "icon" + i + ".png";
}
alert(landmarks['hospital'].image); // displays "icon0.png"

Do you really need those variables? Can't you do with this:
var types = ['hospital','church','library','store'];
for(var i =0; i < types.length; i += 1) (new google.maps.Icon()).image = "icon" + i + ".png";
Modifications done based on comment:
icon name pattern changed from icon + index + .png to icon + type + .png
and saving the results of the loop.
types = ['hospital','church','library','store'];
var landmarks = {};
// images names are of the form icon + type + .png
function createIcon(type)
{
var icon = new google.maps.Icon();
icon.image = "icon" + type + ".png";
return icon;
}
// mapping of landamarks by type and icon
for (var i = 0, len = types.length; i < len; i++)
{
landmarks[types[i]] = createIcon(types[i]);
}
the result is :
{
hospital : icon,
church : icon,
...
}
where icon is a google map icon that has an image attribute that is a string of the form "icon{type}.png" , e.g, iconhostpital.png, iconchurch.png.
To use the icons write landmarks.type where type is one the names in the array of types, e.g. landmarks.hospital.
if the image names are of the form icon + number + .png, and the number for each type is equivalent to its index in the array replace the call createIcon(type[i]) for createIcon(i).

Related

For each element in array-json object

1) What I want is to have:
element1 = [roof, walls, floor]
element2 = [table, chair]
2) My starting point is:
for(var i=0;i<roomElements;i++){
var room = [];
room.push({"element" + i + : getElement(room)});
}
"i" ruins the party. How can I append a dynamic variable to my json array?
I need room to be an object like:
var room = {"element1":"roof,walls,floor","element2":"table,chair"};
And then I want to process that object -somehow- so I can get:
element1 = [roof, walls, floor]
element2 = [table, chair]
And then I want to echo these new variables with something like.
for each element in room
So I can output:
alert("element 1 has roof, walls,floor", "element2 has table, chair")
You can't (before ES6) use dynamic field names like that.
Instead of room.push({"element" + i + : getElement(room)});, you would need:
var foo = {};
foo["element" + i] = getElement(room);
room.push(foo);
With ES6, you can use calculated property name, so
room.push({["element" + i]: getElement(room)});
becomes legal.
Because you're reinitializing elem each iteration, that still won't do exactly what you wanted. It would probably work better to take each of your starting arrays, join their elements, and create a finished object of the results:
var json = {
element1: element1.join(','),
element2: element2.join(',')
};

Pushing object to array results in same value

I have the following javascript code that does not work as I would expect it to. I have a list of checkboxes of which two of the items are "TestDuration" and "AssessmentScores". I'm trying to iterate through the list (which works fine) and have it add the values that are checked to the array.
var SAIndex = 0;
var SSIndex = 0;
var ScoresIndex = 0;
var SubAssessments = [];
var SubAssessmentScores = [];
//Get to the container element
var SSList = document.getElementById("islSubAssessmentScore_container");
//turn it into an array of the checkbox inputs
SSList = SSList.getElementsByTagName("input");
//create a temporary object to store my values
var tempPair = new Object();
//iterate through the checkbox lists
for(var i = 1; i < SSList.length;i++)
{
//if the value is checked add it to the array
if (SSList[i].checked)
{
var P = SubAssessments[SAIndex];
var V = SSList[i].value;
//tempPair.Parent = SubAssessments[SAIndex];
tempPair.Parent = P;
//tempPair.Value = SSList[i].value;
tempPair.Value = V;
//show me the values as they exist on the page
alert(tempPair.Parent + "|" + tempPair.Value);
SubAssessmentScores.push(tempPair);
//show me the values I just added to the array
alert(SubAssessmentScores.length-1 + "|" + SubAssessmentScores[SubAssessmentScores.length-1].Parent + "|" + SubAssessmentScores[SubAssessmentScores.length-1].Value);
//uncheck the values so when I refresh that section of the page the list is empty
SSList[i].checked = false;
}
}
//output the list of objects I just created
for (i = 0;i < SubAssessmentScores.length;i++)
alert(i + "|" + SubAssessmentScores[i].Parent + "|" + SubAssessmentScores[i].Value)
Now what happens is that when I iterate through the list I get the following alerts:
-first pass-
StudentID|TestDuration
0|StudentID|TestDuration
-second pass-
StudentID|AssessmentScores
1|StudentID|AssessmentScores
This is what I expect to output... However at the end of the code snippet when it runs the for loops to spit out all the values I get the following alerts...
0|StudentID|AssessmentScores
1|StudentID|AssessmentScores
I can't for the life of me figure out why it's replacing the first value with the second value. I thought it might be using a reference variable which is why I added in the P and V variables to try to get around that if that was the case, but the results are the same.
This is because you are adding the same variable every iteration of the loop.
Try changing your push like this:
SubAssessmentScores.push({
Parent: P,
Value: V
});
That said, I recommend you study a little more javascript and conventions in the language, for example your variable naming is frowned upon because you should only use capital letters on the beginning of a name for constructor functions.
A good book is Javascript the good parts by Douglas Crockford.

Javascript create object with property as dynamic objects

I tried a lot searching and didnt get desired solutions.
What I want to achieve is
var myObject {
id1 : {
name:place_name,
location : place_loc
},
id2 : {
name:place_name,
location : place_loc
},
id3 : {
name:place_name,
location : place_loc
}
}
What I want to do is that Initially I want the properties "id1", "id2".. to be dynamic. And then dynamically assign name:place_name and other properties of each property.
I dont know the number of properties (id1,id2,id3...) hence would like to add them dynamically and following the addition of properties(id1,id2... ) I want to dynamically add the property values. (place_name & place_loc) of each id.
My code looks something like this.
var myObject = {};
myObject[idnumber1].place = "SomePlace1";
myObject[idnumber1].place = "SomeLoc1";
myObject[idnumber2].place = "SomePlace1";
myObject[idnumber2].place = "SomeLoc1";
But it gives error.
I know it seems simple doubt but any help would be grateful.
Thanks in advance. :)
You are trying to set a value of already assigned objects at keys "idnumber1", etc.
What you'll need is to initialize each objects for your ids like this:
var myObject = {};
myObject[idnumber1] = {};
myObject[idnumber1].place = "SomePlace1";
myObject[idnumber2] = {};
myObject[idnumber2].place = "SomeLoc1"
I would do it this way, it's not exactly what you did ask for, but I think it will become easier to change this later on.
function Place(name, location) {
this.name = name;
this.location = location;
}
var myObject = {}
myObject['id1'] = new Place('Foo', 'Bar');
myObject['id2'] = new Place('Internet', 'test');
console.log(myObject);
To dynamically create objects in your collection, you can use a numerical counter variable to create your object collection (myObject["id" + i] = {name: place_name, location: place_loc}).
An example:
var myObject = {};
for (i = 0; i < 20; i++){
myObject["id" + i] = {name: place_name, location: place_loc}
}
In practice, you can use a counter that you increment outside of a loop.

Is there a way to make a dynamic variable name based on the value of another variable?

Is there a way to make the value of a variable the name for another variable? For example, I want the variable name (value_of_i) to be what ever number "i" is during that iteration. The while loop below is not what I'm using it for, it's just to explain what I'm asking.
var i = 1;
while(i<10)
{
var value_of_i = "This loop has ran " + i + "times.";
i++;
}
For the first iteration, "i" is equal to 1 so I would want the variable name to be "1":
var 1 = "This loop has ran " + i + "times.";
And the second interation:
var 2 = "This loop has ran " + i + "times.";
Yes. Using bracket notation (Here is a tutorial in MDN)
Here is a working fiddle
When doing something like containingObject[stringVariable] you are accessing the property in containingObject whose name is the value stored in stringVariable.
// this assumes browser JavaScript where window is the global namespace
// in node.js this would be a little different
var i=0;
while(i<10){
window["counters"+i] = "This is loop has ran " + i + "times.";
i++;
}
console.log(counters3);
If you'd like you can use this instead of window, however this might fail in strict mode.
Here is the main explanation of how bracket notation works from the MDN link above:
Properties of JavaScript objects can also be accessed or set using a bracket notation. Objects are sometimes called associative arrays, since each property is associated with a string value that can be used to access it. So, for example, you could access the properties of the myCar object as follows:
myCar["make"] = "Ford";
myCar["model"] = "Mustang";
myCar["year"] = 1969;
You can also access properties by using a string value that is stored in a variable:
var propertyName = "make";
myCar[propertyName] = "Ford";
propertyName = "model";
myCar[propertyName] = "Mustang";
You can't make a variable name a number, its not a valid name. So var 1="" is invalid.
But to dynamically set the value you can do
var x = "variablenamehere";
window[x] = "variablevaluehere";
Thats the same as
var variablenamehere
except that it will be scoped as a global variable and will be accessible everywhere, rather than being limited to the current function scope.
Why not store your strings in an array that is indexed by i?
That way you can reference them later efficiently and easily;
var loopI = new Array();
for(var i = 0; i < 10; ++i) {
loopI[i] = "This loop has ran " + i + "times.";
}
This works:
var o = {};
var d = "dog";
for (var k = 0; k < 5; k += 1) {
o[d+k] = k*100;
}
console.log(o.dog3); // 300
This comes closer to doing what you want:
var N = {};
var M = {};
var i = 1;
while(i<10)
{
N[i] = "This loop ran " + i + " times.";
// Or, so you can use dot notation later:
M['OO'+i] = "This loop ran " + i + " times.";
// Those are capital O's, not zeros. Numbers won't work.
i++;
}
console.log(N[3]); // This loop ran 3 times.
console.log(M.OO7); // This loop ran 7 times.
The 'OO' notation could cause bewilderment and wasted time for others trying to use your code; but it could also be a source of amusement for them. This reminds me of a chess board after white's first two moves are to bring out a knight and then put it back. The board then seems to show that black moved first, and some people will endlessly insist that the configuration proves there was illegal play unless someone tells them what happened.

Creating objects of unknown size NOT using eval

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.

Categories