For each element in array-json object - javascript

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(',')
};

Related

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.

Add Array Objects to HTML Table

I am trying to add objects to this set of HTML code.
<div id="output">
<table id="presidents">
<tr>
<th>President</th><th>Took office</th><th>Left office</th>
</tr>
</table>
</div>
Write a function displayTable(presidents) which takes an array of
president objects. Each president object has the properties name,
tookOffice, leftOffice.
For each president add a row to the table with id "presidents"
Place the name in the first column, tookOffice in the second column,
and leftOffice in the third column.
So far this is as close as I have gotten:
var x = document.getElementById('President');
var y = document.getElementById('Took Office');
var z = document.getElementById('Left Office');
function displayTable(presidents) {
var presArray = [{
name: 'W',
tookOffice: '2000',
leftOffice: '2008'
}, {
name: 'Obama',
tookOffice: '2008',
leftOffice: '2016'
}];
for (var i = 0; i < presArray.length; i++) {
x = +presArray[i].name;
y = +presArray[i].tookOffice;
z = +presArray[i].leftOffice;
}
}
Your current code
ID elements
Let's start off by seeing where you've gone wrong:
var x = document.getElementById('President');
var y = document.getElementById('Took Office');
var z = document.getElementById('Left Office');
You're thinking of each of the headers as IDs - the only one that has an ID is the table, because it has
<table id="presidents">
as the attribute. Because you're going to have to create a new row anyway, this isn't the right way to go about it. If that was indeed the case that the IDs corresponded to the table headers, you'd just be overwriting the headers, which of course is wrong. What happens when you run document.getElementById, passing an ID that exists, say:
document.getElementById('presidents'); // capitalisation matters!
is that a JavaScript object that represents the HTML of the <table id="presidents"> element is returned. Using this object, you can call various methods (such as appendChild()) and also properties like innerHTML and outerHTML, which returns the stringifed representation of the element.
For an example HTML file like this:
<!DOCTYPE html>
<html>
<head>
<title>Test page</title>
</head>
<body>
<div id="example">This is an example document.</div>
</body>
</html>
Calling innerHTML on the div element with ID example will yield the following:
document.getElementById('example').innerHTML; // 'This is an example document.'
document.getElementById('example').outerHTML; // '<div id="example">This is an example document.</div>'
You can also assign to these properties (which updates the respective HTML of that element), however it's not always the best idea (due to security concerns), and especially bad in production environments. For a university course though or just a simple hobby project, it should suffice for now.
Assigning values
for (var i = 0; i < presArray.length; i++) {
x = +presArray[i].name;
y = +presArray[i].tookOffice;
z = +presArray[i].leftOffice;
}
Here, instead of adding to the header row (which it makes it messy and does not produce the result intended), you've actually done something completely different - you've made the various variables into something else.
The unary + operator (a + before a value or a variable, without something else on the left of the +) actually coerces the value into a number, which means that it will attempt to convert it into a number, and if not, make it NaN (not a number). For example, see these:
var a = 'random text';
var b = '1234567890';
+1; // 1
+'fefefjejfj'; // NaN
+Infinity; // Infinity
+-Infinity; // -Infinity
+''; // 0
+null; // 0
+undefined; // NaN
+'1.1'; // 1.1
+window; // NaN
+a; // NaN
+b; // 1234567890
If you need to manipulate strings, you need to use the += operator:
var a = 'test';
a += ' string';
a; // 'test string'
However, since you need to write this to the HTML instead of just working with JavaScript variables, what you actually need to be doing is appending new rows to your table, instead of overwriting variables. This can be done using the DOM - there are numerous reference guides and tutorials out there if you need some more help with it.
Your array
var presArray = [{
name: 'W',
tookOffice: '2000',
leftOffice: '2008'
}, {
name: 'Obama',
tookOffice: '2008',
leftOffice: '2016'
}];
The task that you've been given asks for a presidents variable for the argument. This means that you should pass the array when you call the function, not create one inside the function.
A method of passing an array as a argument is like the following:
var x = [ { y: 1 } ];
function test(arg) { return arg[0].y; }
test(x); // 1
Example code
Here's my implementation of the requirements - take the idea of how it works and apply that to your own work.
function displayTable(presidents) {
// get the table to add rows to
var table = document.getElementById('presidents');
// cycle through the array for each of the presidents
for (var i = 0; i < presidents.length; ++i) {
// keep a reference to an individual president object
var president = presidents[i];
// create a row element to append cells to
var row = document.createElement('tr');
// properties of the array elements
var properties = ['name', 'tookOffice', 'leftOffice'];
// append each one of them to the row in question, in order
for (var j = 0; j < properties.length; ++j) {
// create new data cell for names
var cell = document.createElement('td');
// set name of property using bracket notation (properties[j] is a string,
// which can be used to access properties of president)
cell.innerHTML = president[properties[j]];
// add to end of the row
row.appendChild(cell);
}
// add new row to table
table.appendChild(row);
}
}
I've placed a live example of this working on JSFiddle - JSFiddle allows others to show examples and change them as they like.
Can use use innerhtml property to set element contents, so instead of
x += presArray[i].name
should read
document.getElementById('President').innerHTML = presArray[i].name
Also your html th element should have an id of President for this to work..

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.

Why couldn't i insert the same element into an array in javascript?

I have a array of objects. But when I insert the object the I previously added, it will override my previous object. how can I solve it?
I have on object called player. In player, I have two array : one called onHandWeapon, one called onFieldWeapon. They are array of weapon object.
function player(lp){
this.lp = lp;
this.onFieldWeapon = new Array();
this.onHandWeapon = new Array();
}
function weapon(id, heart, bullet, src){
this.id = id;
this.heart = heart;
this.bullet = bullet;
this.src = src;
this.location;
this.name;
this.discription;
this.bufferBullet = bullet;
}
I have set three dummy object in onHandWeapon array. Then I want to randomly pick up one of them and put it into onFieldWeapon and assign a random location to it.
function aiCreateWeapon(){
var b = Math.floor(Math.random()*ai.onHandWeapon.length);
$('#console').append(' ' + b + ' ');
var ip = 100;
while($('#'+ip).attr('class') != 'enemyField'){
ip = Math.floor(Math.random()*48);
}
encurrentWeapon = ai.onHandWeapon[b];
var source = encurrentWeapon.src;
var oImg = document.createElement("img");
oImg.setAttribute('src', source);
oImg.setAttribute('height', '60px');
oImg.setAttribute('width', '60px');
$('#'+ip).append(oImg).show('explode','slow');
encurrentWeapon.location = ip;
ai.onFieldWeapon.push( encurrentWeapon);
$('#console').append(' ' + ai.onFieldWeapon[0].location + ' ');
}
aiCreateWeapon is a function bind to a button. When I click it, the ai.onFieldWeapon[0].location is a fixed location until it changes. I have check that every time when the object which is same as the first element, is added to the onFieldWeapon Array, it will override the first element's data.
When you insert the same object into an array multiple times, you'll have multiple entries in the array that are all references to the same underlying object. In the following example all three entries in myArray and the x and y and myObj variables all point to the same underlying object, so if you change the properties of the object via one of the array items it's not that it updates the other array items too, it is that the other array items point to the same object you just changed:
var myObj = { "p1" : "v1", "p2" : "v2" };
var myArray = [];
// all of the following reference the same underlying object as myObj,
// not copies of myObj.
myArray.push(myObj);
myArray.push(myObj);
myArray.push(myObj);
var x = myObj,
y = myObj;
myArray[1].p1 = "new value";
alert(myArray[0].p1); // "new value"
alert(x.p1); // "new value"
It sounds like what you want to do is create a copy of the object each time so that each item in the array is an independent object that you can update without affecting all the others. Unfortunately there is no built-in way to do that in JavaScript. Fortunately it's not particularly difficult to write your own object copying function, especially in your case where you seem to have only a one-dimensional object:
function copyObject(srcObj) {
// create new blank object and copy the direct properties one by one
var newObj = {};
for (var k in srcObj)
if (srcObj.hasOwnProperty(k))
newObj[k] = srcObj[k];
return newObj;
}
var myObj = { "p1" : "v1", "p2" : "v2" };
var myArray = [];
// make independent copies instead of just more references to the same object
myArray.push(copyObject(myObj));
myArray.push(copyObject(myObj));
myArray.push(copyObject(myObj));
var x = copyObject(myObj),
y = copyObject(myObj);
myArray[1].p1 = "new value";
alert(myArray[0].p1); // "v1"
If you have objects that contain objects or arrays then your copyObject() function needs to be more complicated - usually some form of recursion would be used.

Is there an easy way to create dynamic variables with 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).

Categories