In an array of named objects in javascript - are the names accessible? - javascript

If we create some objects, and fill an array with those objects, are the names stored within the array, or only the properties of the object?
I guess this may be trivial, but I haven't been able to find an answer.
var boxA = {color: "red", width: 100};
var boxB = {color: "yellow", width: 200};
var boxC = {color: "blue", width: 300};
boxArray = [boxA, boxB, boxC];
for (var i = 0; i < boxArray.length; i++) {
//****
// What code do we insert here to log
// boxA
// boxB
// boxC
//****
}
Of course, it is a trivial workaround to add
boxA.box = boxA;
etc and then call
console.log(boxArray[i].box);
But is that really necessary?

To answer your question directly - no, you can't do what you're asking. I've run into the same scenario a few times. Here's what I've done. Instead of using an array, you could just add your objects to an object literal instead, and map the object to some unique key, such as an id.
var boxes = {
boxA: { color: 'red', width: 100 },
boxB: { color: 'blue', width: 200 },
boxC: { color: 'yellow', width: 300 },
};
for (var boxKey in boxes) {
console.log(boxKey);
}
// to use
boxes.boxA; // do something with boxA

No, that does not work like that.
The variable name is a reference to an object in a heap area of memory managed by JS automatically for you.
In details it means that:
var boxA = {color: "red", width: 100};
this statement:
Creates an object in the heap
Associates a local symbol boxA with that object.
So the object is referenced by one variable yet.
var boxArray = [boxA];
here:
An array with one element is created. That element contains a reference to an object. A copy of the reference to be precise. So, the same original object is referenced twice now.
A boxArray is assigned a reference to the array, which is also placed in the heap.
To summarize: the variable names exist only in code listing for developers to easier reason about some objects in memory, instead of operating with memory addresses (which would be horrible).

Well the boxArray is filled with values of variables you are putting in it. Example:
If you would save three integer variables not the names of variables. So your new boxArray is equal to:
boxArray = [{color: "red", width: 100},{color: "yellow", width: 200},{color: "blue", width: 300}];

If you're looking to get the keys of an object try Object.keys(object)
Object.keys(boxA)
["color", "width"]

Your variable names are not accessible to the executing code, but if you need to be able to do this you can nest the objects:
var boxes = {
boxA: {
color: "red",
width: 100
},
boxB: {
color: "yellow",
width: 200
},
boxC: {
color: "blue",
width: 300
}
};
Object.keys(boxes).forEach(function(key) {
console.log(key) // boxA, boxB, boxC
console.log(boxes[key]) // {color: "red", width: 100}, etc.
});

Late to the Party but... Since ES6 javascript introduced classes. If classes is an option you could do:
class boxA { constructor() { this.color = "red"; this.width = 100; } };
class boxB { constructor() { this.color = "yellow"; this.width = 200; } };
class boxC { constructor() { this.color = "blue"; this.width = 300; } };
let boxArray = [new boxA(), new boxB(), new boxC()];
for (var i = 0; i < boxArray.length; i++) {
console.log(boxArray[i].constructor.name);
}

Related

Suspension points without some properties

How to use the suspension points without using some properties?
let foo = {
color: 'red',
backgroundColor: 'green',
width: 100,
height: 50,
}
let colors = {...foo} // removing width and height for this variable
Depends on your exact needs but there are two easy things you can do. If you really want to delete the properties from the object, use delete.
let colors = {...foo};
delete colors.width;
delete colors.height;
Otherwise you can set them to null/undefined.
let colors = {...foo, width: null, height: null};

Javascript - how to retrieve a key from dictionary in the Object constructor

currently, I am initializing an object and one of its values is retrieved from the dictionary, in simplified form something like this
var TrailColor = {
red: '#FF0000',
orange: '#FF9900',
yellow: '#FFFF00'
};
function Trail(trailName, trailColor) {
this.trailName = trailName;
this.trailColor = trailColor;
}
var trail1 = new Trail("TrailName", TrailColor.red);
Now I've decided that I want as a part of this object not only the color code, but also a color name. However, I am not sure how to retrieve the color name "inversely" - so I get the one exact key (not the whole array, I know how to get it) depending on the value and put it as a property of the object. Is there some straightforward way to do it, without the need to iterate through the whole array? Thank you.
I'd pass the color name instead of the value in the first place:
function Trail(name, color = 'red') {
this.name = name;
this.colorName = color;
this.color = this._colors[color];
}
Object.assign(Trail.prototype, {
_colors: {
red: '#FF0000',
orange: '#FF9900',
yellow: '#FFFF00'
},
getColorName() {
return this.colorName;
}
});
const trail = new Trail("TrailName", "red");
trail.colorName // => "red"
trail.getColorName() // => "red"
trail.color // => "#FF0000"

vis.js - How to resize nodes at runtime

I would like to resize nodes of a vis.js network at runtime. My goal is to create a slidercontrol to expand all nodes (an labels) or collapse them.
First, I've tried to manipulate the Scaling values.
var options = {nodes: {scaling: {label: {max: 180 , maxVisible: 180}}}};
network.setOptions(options);
But there are no results.
My second idea was to manipulate the value of every single node.
function IncNodeSize(Increment) {
var CurrentNodes = nodesDS.get();
for (var i = 0; i < CurrentNodes.length; i++) {
CurrentNodes[i].value = CurrentNodes[i].value + 100;
}
}
nodesDS.update(CurrentNodes);
}
But this didn't work either.
Has anyone an idea how to resize nodes at runtime?
With the help of the Developer Community I have solved the issue.
At first I had to change the options and than I had to update the nodes (with no datachange)
This two things together changed the sizes.
In my case I simply wanted to resize a single node. I too tried the DataSet.update() method, but to no avail. What did work, however, was to simply set the new property directly on the node object and call Network.setData(). Here's an example:
const nodes = new vis.DataSet([
{ id: 1, label: 'Node 1', shape: 'circle', margin: 20 },
{ id: 2, label: 'Node 2', shape: 'circle', margin: 20 },
]);
const edges = new vis.DataSet([
{ from: 1, to: 2 }
]);
const dta = { nodes: nodes, edges: edges };
const network = new vis.Network(
document.getElementById('graph'),
dta,
{ interaction: { zoomSpeed: 0.2 } }
);
setTimeout(function() {
const node1 = nodes.get(1);
node1.margin = 50;
network.setData(dta);
}, 2000);
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<div id="graph" style="width: 100%; height: 100%"></div>
Notice that I make sure to have a reference to the object (the dta constant) that includes both the nodes DataSet and the edges DataSet, before I start manipulating the node. That way I can call Network.setData() using that dta object.

[possible bug]Values in array as attribute of object set to undefined

I have encountered one of the most bizzare and frustrating behaviours yet. I have sample data:
var nodes = [ //Sample data
{
ID: 1,
Chart: 1,
x: 50,
y: 50,
width: 100,
height: 80,
color: "#167ee5",
text: "Start",
label: "Start",
targets: [2]
},
{
ID: 2,
Chart: 1,
x: 500,
y: 170,
width: 100,
height: 80,
color: "#167ee5",
text: "End",
label: "End",
targets: [3]
},
{
ID: 3,
Chart: 1,
x: 270,
y: 350,
width: 100,
height: 80,
color: "#167ee5",
text: "Mid",
label: "Mid",
targets: []
}
];
for my web application. The issue is with the targets attribute. As you can see it is array. However when I do
console.log(nodes[0]);
and inspect the result in the browser it shows that the value for targets at index 0 is undefined. Same for every other targets that has some values in them (whether 1 or more).
However if I do
console.log(nodes.[0].targets);
it prints out [2]. If I do Array.isArray(nodes[0].targets) it returns false, yet if I do console.log(nodes[0]) and inspect the result in the browser console, it shows that the object prototype is in fact Array and simply the value at index 0 is undefined.
It worked the day before and now it doesn't. The only thing I did was I restructured the object that uses this variable later. But the console log is being called before the object is even instantiated for the first time (and it doesn't change the nodes var anyway, only reads it).
Does anyone have any clues as to what might be causing this behaviour. If it helps I am using Paperscript and this code runs in the paperscript scope (as it did before when everything worked fine).
UPDATE
Ok after more blind debugging I have determined the block of code that causes the issue, how or why is completely beyond me.
Basically I define an object constructor beflow. The constructor loops through the nodes, makes Paperscript shapes and adds the targets to the arbitrary data attribute of the paperJS path object:
function Flowchart(nodes, chartdata) {
//Member vars. They are only used internally
var connections = [];
var shapes = [];
var connectors = [];
//Constructor operations
createShapes(nodes); //If I uncomment this, the problem goes away
//...
function createShapes(nodes) {
nodes.forEach(function (node) { //for each node data entry
console.log(node); //At this point, the targets are screwed up already
var point = new Point(node.x, node.y); //make a PaperJS point for placement
var size = new Size(node.width, node.height); //make a PaperJS size object
var shape = makeRectangle(point, size, 8, node.color); //Pass to the object instantiating function
shape.data = { //Store arbitrary data for programming reference.
ID: node.ID,
label: node.label,
text: node.text,
'connectors': {
to: [],
from: []
},
targets: node.targets //this is undefined
};
console.log(node.targets) //this logs [2] or [3] but not Array[1]...
shapes.push(shape); //Store reference for later
});
shapes.forEach(function (shape) { //loop though all drawn objects
if (shape.data.targets.length > 0) { //if shape has targets
var targets = _.filter(this.shapes, function (target) {
return _.contains(shape.data.targets, target.data.ID);
});
for (var i = 0; i < shape.data.targets.length; i++) {
shape.data.targets[i] = targets[i]; //Replace the ID-type reference with drawn object reference
}
}
});
}
//... The rest of the object
}
console.log(nodes);
//It doesnt seem to matter whether i put this before or after instantiating.
//It doesnt even matter IF I instantiate in the first place.
var chart = new Flowchart(nodes, chartdata);
This behaviour has been caused by the changes to how Chrome treats enumerable properties of objects. Because Chrome updates silently, it's impossible to notice.
It must have been causing me a lot of headache if I remembered the cause after all this time... (Also it's embarrassing how bad I was at writing questions, but I guess that I realise it means I have progressed since then somewhat).

How to create and organize a JavaScript array?

I am using ColdFusion 8 and jQuery 1.8.
I have some info coming out of a database and being populated into divs like this:
<div class='SpecInfo' data-height='10' data-width='23' data-length='156'></div>
<div class='SpecInfo' data-height='20' data-width='21' data-length='159'></div>
<div class='SpecInfo' data-height='30' data-width='25' data-length='154'></div>
<div class='SpecInfo' data-height='40' data-width='27' data-length='155'></div>
<input type='button' id='GoButton' value='Go!'>
I need to pull out that information and put it into an array and pass it to a CFC. I have a function that collects the data. It looks like this:
// SET VARS
$GoButton = $("#GoButton"),
SpecArray = {
Height: [],
Width: [],
Length: []
};
// GO
var go = function() {
var $SpecInfo = $(".SpecInfo"),
SpecInfoLen = $SpecInfo.length,
H,
W,
L;
for (i = 0; i < SpecInfoLen; i++) {
var H = $SpecInfo.eq(i).data('height'),
W = $SpecInfo.eq(i).data('width'),
L = $SpecInfo.eq(i).data('length');
// add H,W,L values to spec array
SpecArray['Height'].push(H);
SpecArray['Width'].push(W);
SpecArray['Length'].push(L);
}
// stringify spec array
// pass spec array to cfc
alert(SpecArray['Height'].length);
}
$GoButton.click(go);
What this gives me is an array of heights, an array of widths, and an array of lengths. This is not what I want. My info is organized like this
[10,20,30,40]
[23,21,25,27]
[156,159,154,155]
For each div, I want all of the attributes in a single place. I want something more like this:
[10,23,156]
[20,21,159]
[30,25,154]
[40,27,155]
What am I doing wrong? How do I organize my array?
So why do you put all the data in 3 separate arrays instead of an array of objects?
Instead of
SpecArray['Height'].push(H);
SpecArray['Width'].push(W);
SpecArray['Length'].push(L);
use
SpecArray.push( { 'height': H, 'width': W, 'length': L } );
This results in an array of objects like the following:
[
{ 'height': 10, 'width': 23, 'length': 156 },
{ 'height': 20, 'width': 21, 'length': 159 },
{ 'height': 30, 'width': 25, 'length': 154 },
{ 'height': 40, 'width': 27, 'length': 155 }
]
You have to init SpecArray as an array, though, and not as an object containing 3 arrays.

Categories

Resources