how to pass additional properties through Dagre? - javascript

I'm using Dagre to layout my graph and need to send additional properties through to set class/style later in cytoscape.
var graph = new dagre.graphlib.Graph({...});
graph.setEdge(source, target, {
val1: 'foo'
}, e.value);
How to access the additional property val1 later when iterating through edges using graph.edges()?

If I understand it right you should probably be able to get it like that:
var edges = graph.edges();
var i;
for (i = 0; i < edges.length; i++) {
// do stuff
var data = edges[i].data().val1;
// or
var data = edges[i].data('val1');
// or get all attributes
var data = edges[i].data();
//do other stuff
}

Related

Create dynamic variable names and values using for loop: JavaScript

I have a list of values that I want to dynamically assign to another list of values:
var activeMachines = [41,44,46]
for(i = 0; i < activeMachines.length; i++){
var temp + activeMachines[i] = document.getElementById("tempData"+activeMachines[i]);
var humid + activeMachines[i] = document.getElementById("humidData"+activeMachines[i]);
var time + activeMachines[i] = document.getElementById("timeData"+activeMachines[i]);
}
What I am hoping to achieve is that this loop would create 6 new variables in total:
temp41 = document.getElementById("tempData41");
temp44 = document.getElementById("tempData44");
...
Above is not working. I have read some other posts suggesting using arrays, but I think I need to somehow dynamically create a dictionary, and I can't seem to get the syntax right to achieve this. any suggestions?
Anytime you're struggling to dynamically define variable names it's an indication that you should step back and reconsider your data structures. It's almost always the wrong choice that leads to difficult, messy code.
In this case it looks like you have three things that have an id and a temp, humidity and time property. This is exactly what objects are for.
For example you might represent the data like:
let data = { machine_41: {temp: 40, humid: 10, time: 200},
machine_44: {temp: 30, humid: 15, time: 500},
} // etc
Now all your data is in one place and you can access it with simple properties:
data.machine_41.temp
To go from your array of numbers to this object is simple with reduce():
var activeMachines = [41,44,46]
let data = activeMachines.reduce((obj, machineID) => {
// some fake data
temp = 20 // or document.getElementById etc..
humidity = 10
time = 600
obj['machine_'+machineID] = {temp, humidity, time}
return obj
}, {})
console.log("machine_41 humidity:",data.machine_41.humidity)
console.log(data)
This might not be the exact data structure you need (maybe it's better as an array for example), but this approach will serve you better than trying to create a bunch of individual variables.
You can use the window object for doing that, however, I recommend you to create your own object to store those "variables" as properties within that new key-value object.
var activeMachines = [41,44,46]
var obj = {};
for(i = 0; i < activeMachines.length; i++){
obj['temp' + activeMachines[i]] = document.getElementById("tempData"+activeMachines[i]);
obj['humid' + activeMachines[i]] = document.getElementById("humidData"+activeMachines[i]);
obj['time' + activeMachines[i]] = document.getElementById("timeData"+activeMachines[i]);
}
Try this
var activeMachines = [41,44,46];
var output = {};
for(i = 0; i < activeMachines.length; i++){
output["temp" + activeMachines[i]] = document.getElementById("tempData"+activeMachines[i]);
output["humid" + activeMachines[i]] = document.getElementById("humidData"+activeMachines[i]);
output["time" + activeMachines[i]] = document.getElementById("timeData"+activeMachines[i]);
}
console.log(output);
All your variables are define in this variable.
Access like output['temp41']
You can use an object and create properties instead of variables.
var context = {};
for (i = 0; i < activeMachines.length; i++) {
context[`temp${activeMachines[i]}`] = document.getElementById("tempData"+activeMachines[i]);
}
And the access those data with context.temp41 or context["temp41"]

Issue with returning values from an object array

I'm pretty new (a few weeks in) to js and have a question about an incremental game I'm developing. My issue has to do with creating an array from an object I have and then fetching a property of the object, which is used in a compare statement and updated in my HTML.
I have the following object called UPGRADES:
var UPGRADES = {
newClothes: {
name: "New Clothes",
desc: "Give your bums a new look and some more motivation! \n Bum
production bonus: 100%",
moneyCost: 1000,
scienceCost: 10,
requiredScience: 10,
buildingAffected: BUILDINGS.bumBuilding,
upgVal: 2,
id: 'newClothes'
},
//{upgrade 2}
//{upgrade 3 etc.}
}
For one part of my code I need to go through each element of UPGRADES, return the nth object WITHIN "upgrades" (with newClothes as index 0), and then call (Nth index.scienceCost).
So far I've done the following:
var numBuildings = objectLength(BUILDINGS);
var numUpgrades = objectLength(UPGRADES);
function checkVisiblityOnUpgrades () {
var upgArray = [];
for (var a = 0; a < numUpgrades; a++) {
upgArray[a] = Object.keys(UPGRADES)[a].toString();
console.log(UPGRADES.upgArray[a]);
if (UPGRADES.upgArray[a].requiredScience <= resources.science) {
var idString = upgArray[a].id.toString();
getId(idString.concat("Button")).style.visibility = "visible";
getId(idString.concat("MoneyCostDisp")).innerHTML =
numFormat(upgArray[a].moneyCost);
getId(idString.concat("ScienceCostDisp")).innerHTML =
numFormat(upgArray[a].scienceCost);
}
}
}
I get this error along with it:
Uncaught TypeError: Cannot read property '0' of undefined
at checkVisiblityOnUpgrades (game.js:268)
at update (game.js:290)
268 is console.log(UPGRADES.upgArray[a]);
I was wondering how I would actually go about grabbing the values of the object I wanted. I'm creating an array in checkVisibilityOnUpgrades() so I can iterate through each upgrade with a for loop.
Another question I have is: If I was going to store 100+ instances of upgrades, would it be better to switch UPGRADES to an array rather than its own object? That way I could grab values a lot more easily.
You can drastically simplify your initial logic there with Object.entries:
Object.entries(UPGRADES).forEach(({ key, thisUpgradeObject }) => {
// `key` references the outer property, eg., 'newClothes'
// `thisUpgradeObject` references the inner object
});
So
Object.entries(upgArray).forEach(({ key, obj }) => {
const {
requiredScience,
id,
moneyCost,
scienceCost,
} = obj;
if (requiredScience < resources.science) return;
const idString = id.toString();
getId(idString.concat("Button")).style.visibility = "visible";
getId(idString.concat("MoneyCostDisp")).innerHTML = numFormat(moneyCost);
getId(idString.concat("ScienceCostDisp")).innerHTML = numFormat(scienceCost);
});
I see the problem here:
You create an array called upgArray, but then try to access UPGRADES.upgArray which is undefined. What you want to write there is likely UPGRADES[upgArray[a]].
function checkVisiblityOnUpgrades () {
var upgArray = Object.keys(UPGRADES);
for (var a = 0; a < numUpgrades; a++) {
if (UPGRADES[upgArray[a]].requiredScience <= resources.science) {
var idString = UPGRADES[upgArray[a]].id.toString();
getId(idString.concat("Button")).style.visibility = "visible";
getId(idString.concat("MoneyCostDisp")).innerHTML =
numFormat(UPGRADES[upgArray[a]].moneyCost);
getId(idString.concat("ScienceCostDisp")).innerHTML =
numFormat(UPGRADES[upgArray[a]].scienceCost);
}
}
}

Get and set object values in localStorage array

I'm trying to set objects into localStorage with a format similar to the following:
[{"1":{"property1":false,"property2":false}},{"2":{"property1":false,"property2":false}}]
Where I'd be able to set the 1 or 2 based on a dynamic value I'm getting from a REST call. What I have so far is:
// check if session exists and create if not
var StorageObject = JSON.parse(localStorage.getItem("session")) || [];
//see if the current id from the REST call is in storage and push with properties if not
if ( !StorageObject[thisItemsListID] ) {
var itemProperties = {};
itemProperties[thisItemsListID] = {};
itemProperties[thisItemsListID]["property1"] = false;
itemProperties[thisItemsListID]["property2"] = false;
StorageObject.push(itemProperties);
localStorage.setItem('session', JSON.stringify(StorageObject));
}
I can get the data into localStorage using this format but StorageObject[thisItemsListID] always gets into the if statement and generates a duplicate item in localStorage and I'm not sure how to access this with a variable. I'm trying to append the new ID if it doesn't exist so if {1:{} exists but current ID is 2 I need to push the new value.
I'm close here and maybe I need to reevaluate the format I'm storing the data string but I'm going in circles here and could use a point in the right direction.
Well, the duplicate item is happening in StorageObject.push(itemProperties).
Try this to update the object:
//StorageObject.push(itemProperties); <-- remove
StorageObject[thisItemsListID] = itemProperties;
[EDIT]
If you want to keep [{"1":{"property1":false,"property2":false}},{"2":{"property1":false,"property2":false}}]. To conditional would be a bit different.
var haveItem = StorageObject.filter(function(item){
return Objects.keys(item)[0] == thisItemsListID;
}).length > 0;
if ( !haveItem ) {
var itemProperties = {};
itemProperties[thisItemsListID] = {};
itemProperties[thisItemsListID]["property1"] = false;
itemProperties[thisItemsListID]["property2"] = false;
StorageObject.push(itemProperties);
localStorage.setItem('session', JSON.stringify(StorageObject));
}
Are you trying to update the object or just overwrite it? Filipes response illustrates how to update the entire storage object by just reassigning the object with the new value.
If you wanted to update just as section/ value of the object you could do so using a for loop. This would allow you to scan the array locate the one property and then remove it, updated it, overwrite it etc.
Here is an example of the loop. Bear in mind This is a snippet from a report library I was building. It uses angular $scope but it is a complex type doing a similar action to your update (here I am setting a label as a favorite/bookmark)
function OnFavoriteComplete(response) {
var id = response.config.data.reportId; //dynamic values set by client
var isFavorite = response.config.data.isFavorite;//dynamic values set by client
var arrayCount = $scope.reportList.length;
//loop my current collection and look for the property id of the label
//then check to see if true or false/this was a toggle enable disable
if (isFavorite) {
for (var i = 0, iLen = arrayCount; i < iLen; i++) {
if ($scope.reportList[i].reportId == id) {
$scope.reportList[i].isFavorite = false;
}
}
}
//if false update the property with the new value
else {
for (var i = 0, iLen = arrayCount; i < iLen; i++) {
if ($scope.reportList[i].reportId == id) {
$scope.reportList[i].isFavorite = true;
}
}
}
};
If you are using another framework like lowDash it has some really nice helper functions for updating and evaluating arrays.

How can I programmatically add to a variably-nested object?

I need a way to add an object into another object. Normally this is quite simple with just
obj[property] = {'name': bob, 'height': tall}
however the object in question is nested so the following would be required:
obj[prop1][prop2] = {'name': bob, 'height': tall}
The clincher though, is that the nesting is variable. That is that I don't know how deeply each new object will be nested before runtime.
Basically I will be generating a string that represents an object path like
"object.secondObj.thirdObj.fourthObj"
and then I need to set data inside the fourth object, but I can't use the bracket [] method because I don't know how many brackets are required beforehand. Is there a way to do this?
I am using jQuery as well, if that's necessary.
Sure, you can either use recursion, or simple iteration. I like recursion better. The following examples are meant to be proof-of-concept, and probably shouldn't be used in production.
var setDeepValue = function(obj, path, value) {
if (path.indexOf('.') === -1) {
obj[path] = value;
return;
}
var dotIndex = path.indexOf('.');
obj = obj[path.substr(0, dotIndex)];
return setDeepValue(obj, path.substr(dotIndex + 1), value);
};
But recursion isn't necessary, because in JavaScript you can just change references.
var objPath = 'secondObj.thirdobj.fourthObj';
var valueToAdd = 'woot';
var topLevelObj = {};
var attributes = objPath.split('.');
var curObj = topLevelObj;
for (var i = 0; i < attributes.length; i++) {
var attr = attributes[i];
if (typeof curObj[attr] === 'undefined') {
curObj[attr] = {};
}
curObj = curObj[attr];
if (i === (attributes.length - 1)) {
// We're at the end - set the value!
curObj['awesomeAttribute'] = valueToAdd;
}
}
Instead of generating a string...
var o="object";
//code
o+=".secondObj";
//code
o+=".thirdObj";
//code
o+=".fourthObj";
...you could do
var o=object;
//code
o=o.secondObj;
//code
o=o.thirdObj;
//code
o=o.fourthObj;
Then you can add data like this:
o.myprop='myvalue';
And object will be updated with the changes.
See it here: http://jsfiddle.net/rFuyG/

Update nested attributes in a JavaScript object

I want to change 'hello' to 'hey' programmatically, the solution should work with any number of nested elements (I just use 2 levels to keep it simple).
var data = {level1: {level2 : 'hello' }};
I have access to the 'data' variable, the path ('level1/level2') and the new value ('hey').
I tried to do:
var parents = 'level1/level2'.split('/');
var target = data;
for(var i=0; i<parents.length; i++){
target = data[parents[i]];
}
target = 'hey';
The idea was to travel to the root
target = data
then 1 level deep
target = data['level1']
...keep going
target = data['level1']['level2'] //data['level1'] === target
and modify the contents
target = 'hey'
But it looks like a lose the reference to the original object (data) when I do (target = target['level2']).
I guess I can build a string with the path and then evaluate it:
eval("data['level1']['level2']='hey');
Is there a better solution that dosen't involve eval()?
There are two issues. First is that you keep using data inside the loop, which means you're trying to access the top level keys instead of the inner keys. Change target = data[parents[i]]; to
target = target[parents[i]];
The second is that when you change the variable target, you're not changing the data variable but target instead. If you drop out of the loop one iteration earlier you can update the object which is stored as a reference:
for(var i=0; i<parents.length-1; i++){
target = target[parents[i]];
}
target[parents[i]] = 'hey';
Demo: http://jsfiddle.net/Lherp/
Try something like this:
var data = {level1: {level2 : 'hello' }};
var parents = 'level1/level2'.split('/');
var target = data;
for(var i=0; i < parents.length - 1; i++){
target = target[parents[i]];
}
target[parents[i]] = 'hey';
Or am I missing something?
edit: I was missing something (sorry, should have tested it first..)

Categories