Dynamically accessing global undefined variables (example in D3), DRY - javascript

Following on from this question, I would like to create a DRY way of creating Js variables for a D3 graph which represents daily sentiment analysis of UK newspapers.
Here is some example code from my script:
var guardian,independent; // many more here
var gLine,gChart; // many more here
var iLine,iChart; // many more here
I am storing the newspaper-specific variables in an object:
var allObjects = { guardian : {line : gLine,chart : gChart},
independent : {line : iLine,chart : iChart}}// and so on for each newspaper
I assign the variables using functions as follows:
function makeLine(name){return d3.svg.line().y(function(d) { return y(d[name]); }); }
// and so on for each newspaper attribute in AllObjects
Rather than repeating myself all the time, making each object individually:
makeLine('guardian'); makeLine('independent'); // etc
...which works fine, I would like to be able to iterate over all the newspapers, and assign the objects with a single function for all newspapers, something like:
var allFunctions = {line: makeLine(),chart: makeChart()};
function make(type){
var myFunc = allFunctions.type;
for(var prop in allObjects){prop.type = myFunc(type);}
}
So that make(line) would assign gLine, iLine, etc
The problem is that as the variables in allObjects.guardian are undefined, this method isn't working.
Any suggestions as how to refactor in this way?

Rather than repeating myself all the time, making each object individually:
makeLine('guardian'); makeLine('independent'); // etc
...which works fine, I would like to be able to iterate over all the newspapers, and assign the objects with a single function for all newspapers
If I'm reading that right, your "something like" is really close, see comments:
var allFunctions = {line: makeLine, chart: makeChart};
// Note no () here ----------------^ or here --------^
// We want the reference to the function, we don't want to call it (yet)
// Assuming `type` is "line", "chart", etc.
function make(type){
// Note brackets: We want the property whose name is in the type
// variable, not a property actually called "type"
var myFunc = allFunctions[type];
// ^----^------ We want the property whose name is in
// the `type` variable, not a property
// actually *called* "type"
for (var prop in allObjects) {
allObjects[prop][type] = myFunc(prop);
// ^----^-----^----------- Brackets again as above
}
}

Related

SSIS Reading Columns from an Object Variable

I have an object variable which is from a SQL Query. This essentially contains two columns: RecordID and Description. I'm not familiar with JavaScript. But how do I read the specific columns and assign them to a local javascript variable?
Here's the sample code I would like to use with the new User::MyObject structure of multiple columns:
task.run = function () {
var myID = task.variables["User::MyObject"].value;
var myDesc = task.variables["User::MyObject"].value;
alert(myID);
alert(myDesc);
return ScriptResults.Success;
};
EDIT: I am using COZYROC that's why I have a JavaScript Task available in my toolbox. The result set is currently set to Full Result Set and the object is being pushed to User::MyObject via a preceeding SQL Task.
Here's a code from when my User::MyObject was a single result set with single row and single column return (just the Description).
task.run = function () {
var myDesc = task.variables["User::MyObject"].value;
alert(myDesc);
return ScriptResults.Success;
};
I know for VB.NET/C# you can use something like myVariable.Rows[0][1].ToString() but i'm really not sure how that translates to JavaScript.
Within your task function:
1. Set a variable to the object
var MyObject= task.variables["User::MyObject"].value;
2 Access the ID property of your object
MyObject.ID
Complete example to get ID:
task.run = function () {
var MyObject = task.variables["User::MyObject"].value;
alert(MyObject.ID);
return ScriptResults.Success;
};
Example from crazycroc documentation https://desk.cozyroc.com/portal/en/kb/articles/how-c

Adding structured data to an Array in JavaScript

I am trying to create sample data to test a form Grid. And am using the following function to try and create the data to send to my grid.
// populateFields: Populates data n times a record of data for the SSM form.
// #params: n, fips, products
// #returns: fields
populateFields(n, fips, products) {
var data = [];
var fields = this.getFields();
for(i = 0; i < n; i++) {
var x = {fields[0]: false,
fields[1]: fips[getRandomInt(0, fips.length())],
fields[2]: products[getRandomInt(0, products.length())],
fields[3]: getRandomInt(0, 100)};
data.push(x);
}
return data;
}
Nothing gets populated when I call it. I get an error saying fields[0]: false needs [ token.
Note: This is part of a class, I don't think that matters.
I am not sure if you want to see how I call it.
Is it because of jQuery, as in what I am passing the array to.
To use a variable as a property key it has to be enclosed in brackets:
{
[fields[0]]: false
//...
}
Otherwise it would try to use field[0] as an identifier itself, and some characters like [ arent allowed in identifiers (cause they are used for property access). (They are allowed in property names though, so { "field[0]": false } would work syntactically, but that makes little sense).

HTML5 Local Storage with saved integers and variables

I'm trying to achieve a function that makes the user able to save a mathematical formula that uses static variables that I've already created and save them with Local Storage.
Then the script fetches that formula from the Local Storage, does the math and displays the results on a table.
I have everything in order, except the fetching part;
as localStorage.getItem() returns a string, and converting it with parseFloat()/parseInt() only returns the first integer or NaN.
Both of this messes up the expected the results.
Is there any way I can get Objects from localStoage that contains both integers and variables?
Heres an example of a formula that should work, fetched by 5 localStorage.getItem() requests.
avgFrags*250
avgDmg*(10/(avgTier+2))*(0.23+2*avgTier/100)
avgSpots*150
log(avgCap+1,1.732)*150
avgDef*150
Any ideas or alternatives?
EDIT:
Each line represents the output of a getItem() request;
form_frag = localStorage.getItem('formula_frag');
form_dmg = localStorage.getItem('formula_dmg');
form_spot = localStorage.getItem('formula_spot');
form_cap = localStorage.getItem('formula_cap');
form_def = localStorage.getItem('formula_def');
localStorage store in a key-value store where every value is pushed to a string. If you are certent that you are handling "integers" you can push the string to a number:
var avgFrags = +localStorage.getItem('avgFrags'); // The + infront pushes the string to number.
I'm not completely sure that I understand your question.
(+"123") === 123
You can convert easily convert your strings to functions if you know the variable names before hand using Function(). The first parameter(s) are your function arguments and the last is your function body.
var func1 = Function('avgFrags', 'return avgFrags * 250;');
This is equivalent to:
function func1(avgFrags) {
return avgFrags * 250;
}
Known Function Signature
If you know what variable names will be used for each item in local storage then it should be easy for you to do what you want with function:
// from your edited question
form_frag = localStorage.getItem('formula_frag');
form_dmg = localStorage.getItem('formula_dmg');
// ... create functions
var fragsFunc = Function('avgFrags', form_frg );
var dmgFunc = Function('avgDmg', 'avgTier', form_dmg );
// ... get frags
var frags = fragsFunc (10); // frags = 2500; // if sample in storage
Unknown Function Signature
Now if you have a limited amount of variable names and you don't know which ones will be used with each function then you can do something like:
var avgFrags, avgDamage, avgTier, avgSpots, avgCap, avgDef;
// ... get from storage
form_frag = localStorage.getItem('formula_frag');
form_dmg = localStorage.getItem('formula_dmg');
// ... create functions
var fragsFunc = Function('avgFrags', 'avgDamage', 'avgTier', 'avgSpots', 'avgCap', 'avgDef', form_frag);
var dmgFunc = Function('avgFrags', 'avgDamage', 'avgTier', 'avgSpots', 'avgCap', 'avgDef', form_frag);
// ... get frags, only the first argument is used, but we don't know that.
var frags = fragsFunc (avgFrags, avgDamage, avgTier, avgSpots, avgCap, avgDef); // frags = 2500; // if sample in storage
You can make this simpler by having just one variable passed into the function which is an object that holds all of the arguments that can be passed to the function. Just have to make sure that the function writer uses that object.
var settings = {
avgFrags: 10,
avgDamage: 50,
// ...
};
var fragsFunc = Function('s', 's.avgFrags * 250');
var frags = fragsFunc (settings);
Getting parts with an regex
I am assuming that the above will get the job done, that you don't really want an object with variable names and numbers and operators.
If you just need the variable names and numbers (and operators) you can use a regex for that.
([a-z_$][\w\d]*)|([0-9]*\.?[0-9]+)|([^\w\d\s])
You can use that to create an array with each part. Also each part is grouped so you know which is a variable name, which is a number, and which is an other (parenthesis or operator)
var re = /(\w[\w\d]*)|([0-9]*\.?[0-9]+)|([^\w\d\s])/g,
match,
results;
while ((match = re.exec(localStorage.getItem('formula_frag'))) {
results.push({
text: match[0],
type: (match[1]) ? 'var' | (match[2]) ? 'number' : 'other'
})
}
You can view the output of the regex with your sample data using REY.
Yes you can set Objects in localstorage
Here is the fiddle for that - http://jsfiddle.net/sahilbatla/2z0dq6o3/
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
var value = this.getItem(key);
return value && JSON.parse(value);
}
$(function() {
localStorage.setObject('x', {1: 2, 2: "s"})
console.log(localStorage.getObject('x'));
});

Accessing an associative array using jQuery

I have an associative array here -
var dataset = {
"person" : [
{"userLabels": ["Name","Role"]},
{"tagNames": ["lName","role"]},
{"tableClass": "width530"},
{"colWidths": ["50%","50%"]}
]
}
I tried accessing the 'userLabels' object using jQuery using various methods but I failed. I think I am doing something wrong with basics. I want the userLabels object to be accessed using jQuery and the result should be an array, so I can perform the jQuery.inArray() operation.
Firstly, here's how you can access dataset using the method you have.
var dataset =
{
"person" : [
{"userLabels": ["Name","Role"]},
{"tagNames": ["lName","role"]},
{"tableClass": "width530"},
{"colWidths": ["50%","50%"]}
]
};
alert(dataset['person'][0]['userLabels']); //style 1
alert(dataset.person[0]['userLabels']); //style 2
alert(dataset.person[0].userLabels); //style 3
//Also you can use variables in place of specifying the names as well i.e.
var propName ='userLabels';
alert(dataset.person[0][propName]);
//What follows is how to search if a value is in the array 'userLabels'
$.inArray('Name', dataset.person[0].userLabels);
I'd like to ask why you're doing this in a such an 'interesting way'. Why don't you just make them all objects?
That's what I would do if I were you because if you think about it, a person IS an object and it should be noted that arrays are basically objects in Javascript with a 'length' property, though I won't elaborate on it here (feel free to do some research though). I'm guessing it's because you don't know how to iterate over object properties. Of course if it makes more sense to you, go for it.
Note one of the differences between an array and an object is that object properties need to be defined; you'll notice that I gave 'Name' and 'Role' values of 'undefined' below.
In any case, here is what I would do:
var dataset =
{
"person" : {
"userLabels": {"Name" : undefined,"Role": undefined},
"tagNames": {"lName" : undefined,"role" : undefined},
"tableClass": "width530",
"colWidths": ["50%","50%"]
}
};
for (var i in dataset) { //iterate over all the objects in dataset
console.log(dataset[i]); //I prefer to use console.log() to write but it's only in firefox
alert(dataset[i]); // works in IE.
}
//By using an object all you need to do is:
dataset.person.userLabels.hasOwnProperty('Role'); //returns true or false
Anyways, hope this helps.
var basic = dataset.person[0].userLabels;
// | | |
// | | --- first element = target object
// | --- person property
// ---- main-object
var userLabels = dataset.person[0].userLabels;
if ($.inArray(yourVal, userLabels) !== -1) {
doStuff();
}

Why does this Javascript example copy the variable value instead of pass by reference?

In Javascript The Good Parts, it states:
So I would expect the following code example to output 1001 since "objects are never copied but passed around by reference", so why does it output 0000?
var page_item = {
id_code : 'welcome',
title : 'Welcome',
access_groups : {
developer : '0010',
administrator : '0100'
}
};
page_item.access_groups.member = '0000';
var member = page_item.access_groups.member;
member = '1001';
$('p#test').html(page_item.access_groups.member); //should be "1001" but is "0000"
Added:
#Gareth #David, thanks, this is what I was trying to show in this example, works:
var page_item = {
id_code : 'welcome',
title : 'Welcome',
access_groups : {
developer : '0010',
administrator : '0100'
}
};
var page_item2 = page_item;
page_item2.access_groups.developer = '1001';
$('p#test').html(page_item.access_groups.developer); //is '1001'
Don't think of pass-by-reference in the C++ context, because it's not the same.
var member = page_item.access_groups.member // Sets member to this value
member = '1001'; // Now sets it to another value
If there was a method on strings which changed them, then this:
member.removeLastLetter();
would alter page_item.access_groups.member. However, with your = you are changing the variable's reference, not the object it previously referenced
Because page_item.access_groups.member is a string and not an Object.
This is probably getting bashed by JS-Gurus but basically it goes down like this:
Objects are passed by reference.
Strings (numbers, etc... basically 1 dimensional variables) are passed by value.
I did try and understand the lengthy explanations on data types but I seriously needed some work done and haven't gotten time to look at it more closely.

Categories