Adding another variable to an array in angularJS - javascript

So im editing some code and I would like to add another variable to an array. The code below works perfectly:
submit.addAttributeValue = function() {
var aValue = submit.status.newAttributeValue;
var aType = submit.status.selectedAttributeType;
console.log('adding value', aValue, aType)
if(aValue && aType ) {
submit.ProductMeta['attributes'][aType][aValue] = true;
};
};
I then add the variable aPrice to the function:
submit.addAttributeValue = function() {
var aValue = submit.status.newAttributeValue;
var aType = submit.status.selectedAttributeType;
var aPrice = submit.status.newAttributePrice;
console.log('adding value', aValue, aType, aPrice)
if(aValue && aType ) {
submit.ProductMeta['attributes'][aType][aValue][aPrice] = true;
};
};
I get the error:
Error: submit.ProductMeta.attributes[aType][aValue] is undefined
submit.addAttributeValue#http://dubdelivery.com/js/controllers-submit.js:369:13
ProductMeta is defined as: submit.ProductMeta = {};
Any advice on how I should approach this?
Thank You!

Your array is empty so you can't set a second level field before the first
If you have
var obj = {};
You have to set
obj.firstItem
before
obj.firstItem.secondItem
Here is an example

Look in the debugger or just console log "aType", "aValue", and "aPrice". I'm betting "aValue" is undefined.
If you're going to go about manipulating object properties this way, you have to make sure the variables that contain your property names actually have values.
(BTW, especially now with ES6 classes, you probably shouldn't be manipulating object property/values this way).

Related

Access dynamically created objects in Javascript

I am attempting to dynamically create an object with name-value pairs using html input fields. This is what i have so far:
var taskComplete = {
newTask: function(arg) {
var fieldObj = {},
selector = arg,
inputFields = document.getElementsByClassName(selector);
for (var i=0;i<inputFields.length;i++) {
var attrValue = inputFields[i].getAttribute("name"),
value = inputFields[i].value,
newFieldObj = fieldObj[i] = {[attrValue]: value };
console.log(newFieldObj);
}
}
}
taskComplete.newTask('input');
The console log outputs:
Object {title: ""}
Object {description: ""}
Object {date: ""}
Question1:
How do i access these objects? they all share the same name eg. 'Object' so 'object.title' does not work.
Question2:
Is there a way to combine these objects into a single object?
eg.
var obj = {
title: "",
description: "",
date: "",
}
code example with html: codepen.io
Hope this make sense. Thank you for any and all assistance.
I will answer your questions in the reverse order, makes more sense, you will see.
Question2: Is there a way to combine these objects into a single object?
Yes, I am happy to inform you that you absolutely can. Where you do
newFieldObj = fieldObj[i] = {[attrValue]: value };
simply do
fieldObj[attrValue] = value;
What this does, is the following: On the fieldObj, which is a plain {} set a key named after the value of attrValue and pair that key with the value value
Question1: How do i access these objects? they all share the same name eg. 'Object' so 'object.title' does not work.
In order to be able to access these objects, your newTask method should be returning them. So, at the end of your newTask method, simply do return fieldObj; like so
var taskComplete = {
newTask: function(arg) {
var fieldObj = {},
selector = arg,
inputFields = document.getElementsByClassName(selector),
attrValue,
value;
for (var i=0;i<inputFields.length;i++) {
attrValue = inputFields[i].getAttribute("name");
value = inputFields[i].value;
fieldObj[attrValue] = value;
}
return fieldObj;
}
}
and then store the returned value to a new variable like so:
var aFancyName = taskComplete.newTask('input');
Here's the modified pen: http://codepen.io/anon/pen/XdjKQJ
Not super clear on what you are trying to do here.
Instead of creating a new object for each iteration of your loop, why not just assign those properties to the fieldObj you already have?
Then you can just return that object and do whatever you want with it in the calling code:
'use strict';
// ** TASK OBJECT ** //
var taskComplete = {
newTask: function(selector) {
var fieldObj = {},
inputFields = document.getElementsByClassName(selector);
for (var i = 0; i < inputFields.length; i++) {
var attrKey = inputFields[i].getAttribute("name"),
value = inputFields[i].value;
fieldObj[attrKey] = value;
}
return fieldObj;
}
}
var o = taskComplete.newTask('input');
console.dir(o);
http://codepen.io/anon/pen/reMLPB?editors=0010

JavaScript prototype, issue in calling function

My prototype definition is below
var DupPlayer = function(strName){
this.name = strName;
}
var FreqTab = function(strMsg,strName){
this.value =strMsg;
this.original = strName;
this.dupPlayers = new Array();
FreqTab.prototype.addDup = function(dup){
this.dupPlayers.push(dup);
}
}
I'm creating array object with string as key.
var freqTab = new Array();
if(freqTab[key]==undefined){
freqTab[key] = new FreqTab(strMsg,strName);
}else{
var temp = freqTab[key];
temp.addDup(new DupPlayer(strName));
}
Getting error "TypeError: temp.addDup is not a function".
Please help me where i got wrong in the function call.
[edit]
Found that this issue occures when the key is 'reduce'. :(
console.log(freqTab[key]) gives below output, only when key is reduce, object is stored as function.
{ value: 'sleeping', original: 'Pug', dupPlayers: [] }
{ value: 'black', original: 'Sur', dupPlayers: [] }
[Function: reduce]
The reason why you are getting the error:
temp.addDup is not a function
Is actually an interesting functionality that happens when you attempt to access a undefined/invalid item inside an array. When you attempt to access:
freqTab["reduce"]
It will actually read it as the actual native reduce() function. The same thing happens with other functions such as freqTab["sort"]. Then it states that addDup is not a method of reduce.
Note in your code the array is empty, and since you are accessing a item by a string you probably rather want to use an object:
var freqTab = { 'reduce': ... };
Specifically you might be looking for:
var freqTab = { 'reduce': new FreqTab(strMsg,strName) };
try to use prototype outside the definition like this
var FreqTab = function(strMsg,strName){
this.value =strMsg;
this.original = strName;
this.dupPlayers = new Array();
}
FreqTab.prototype.addDup = function(dup){
this.dupPlayers.push(dup);
}
As I have explained in my comment, issue is in this condition
Comment: If freqTab[key] is undefined, you are defining it as new object. But if not then its just a simple element of array and not your object. Hence addDup is not available.
var freqTab = new Array();
if (freqTab[key] == undefined) {
freqTab[key] = new FreqTab(strMsg, strName);
} else {
var temp = freqTab[key];
temp.addDup(new DupPlayer(strName));
}
Instead try this:
var freqTab = new Array();
if (freqTab[key] == undefined) {
freqTab[key] = new FreqTab(strMsg, strName);
}
if(freqTab[key] instanceof FreqTab){
var temp = freqTab[key];
temp.addDup(new DupPlayer(strName));
}
else{
console.log("Not an object")
}

How does angular or js return data without specifying a parameter name

The title doesnt really explain what i am trying to ask here. Well here is an example:
.factory('Story', function($http) {
var storyFactory = {};
Factory.getStory = function() {
return $http.get('/api');
}
})
.controller('StoryController', function(story) {
var vm = this;
Story.allStory()
.sucess(function(mydata) {
})
})
So how allStory() returns data into mydata?
Are you asking about the way javascript replaces the written code with the logical object at the time?
eg.
console.log(new Array({"getWalkDetails":function(){return {"MaxSpeed":15, "DistanceWalked": 123}} },
"walking on sunshine",
"oh oh" ).shift().getWalkDetails().MaxSpeed);
//outputs "15" to the console
This can be rewritten as
var arr = new Array();
var func = function(){
var details = new Object();
details.MaxSpeed =15;
details.DistanceWalked = 124;
return details;
}
var obj = {"getWalkDetails" : func};
arr.push(obj);
arr.push("walking on sunshine");
arr.push("oh oh");
var firstItem = arr.shift();
//the array function 'shift()' is used to remove the first item in the array and return it to the variable
var walkingDetails = firstItem.getWalkingDetails()//same as func() or obj.getWalkingDetails()
console.log(walkingDetails.MaxSpeed);//15
As you can see we stored most of the the interpreted outputs as variables to be used seperately.
EDIT:
If you are asking how to pass objects by reference in javascript to allow the mydata variable to receive any changes done to it in the function it is passed to. then this question might be helpful to you:
javascript pass object as reference
EDIT:
edited the code above a bit more
I'm not entirely sure either what you mean (especially because I never worked with Angular), but I have a feeling you're puzzled by this little trick:
//+ fn -> [a]
var getParameterNames = (function () {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,
ARGUMENT_NAMES = /([^\s,]+)/g;
return function (fn) {
var fnStr = fn.toString().replace(STRIP_COMMENTS, ''),
names = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
return names || [];
};
})();
function add (x, y) {
return x + y;
}
console.log(getParameterNames(add)); // => ['x', 'y']
Edit: And here's a jsfiddle.

Unexpected behavior using getters and setters

Look this code:
<script>
function dbg (object) {
var _string = "";
for (var a in object) {
_string += a + ":\n";
for (var b in object[a])
if (/^get_/.test (b))
_string += "\t" + b + " - " + object[a][b] () + "\n";
}
return _string;
}
function Order () {
var products = [];
this.get_products = function () {return products;}
this.set_products = function (_products) {products = _products;}
}
function Product () {
var id = null;
var name = null;
this.get_id = function () {return id;}
this.get_name = function () {return name;}
this.set_id = function (_id) {id = _id;}
this.set_name = function (_name) {name = _name}
}
var order = new Order ();
var product = new Product ();
product.set_id (1);
product.set_name ("Banana");
order.set_products (order.get_products ().concat (product));
alert (dbg (order.get_products ())); // Ok
product.set_id (2);
product.set_name ("Orange");
order.set_products (order.get_products ().concat (product));
alert (dbg (order.get_products ())); // Duplicated values! What?
</script>
The first time you push the object "Product" into the object "Order", everything looks fine.
When you set new values to the object "Product", the object itself overwrites the previous values of the object "Order". The final result is a array of duplicated values. Is it normal ? Is there a workaround? Just tried everything I knew without success. Thanks.
Crazy Train has already answered it in the comments. The question is listed having 0 answers so I'll add it as an answer.
When adding a variable containing an object to an array you add a reference to the variable, when you re assign the variable the reference is broken.
Adding a variable containing an object to an array then re assigning the variable doesn't change the object in the array:
var arr=[];
var object={name:"John"};
arr.push(object);
object=33;
console.log(arr);//=[Object {name="john"}]
Adding a variable containing an object to an array then changing the internal values of the object that the variable contains does change the object in the array:
var arr=[];
var object={name:"John"};
arr.push(object);
object.name="Jane";
console.log(arr);//=[Object {name="Jane"}]
So to correct your code you could do the following:
Create a new variable for the product to be added:
var product2=new Product();
product2.set_id (2);
product2.set_name ("Orange");
order.set_products (order.get_products ().concat (product2));
Or break the reference between your product variable and the products array in order:
product=null;//product has no ref to order.products
product=new Product();
product.set_id (2);
product.set_name ("Orange");
order.set_products (order.get_products ().concat (product));
I would not define members of an object in a constructor function with var as JavaScript doesn't support private members. You can simulate them by creating closures but that has it's own problem when you have instance specific privates (as is your case). You can't use prototype if the functions need to access private instance variables, you can't clone it unless you have public accesssors, inheritance and overriding functions will be a pain.
Here is some more info on using constructor functions.
If you have Chrome or Firefox (with Firebug) then you can press F12 to open the console. You an detach the console window (have it's own window) then copy code in the before mentioned answers and paste them in the commandline of the console. There you can run and re run the code, change and see the output to better understand JS behavior.
You are just overriding the variables in object. I'd do it like this, much simpler:
var products = {
set : function(name,id) {
products.list.push({name:name,id:id});
},
get : function(id) {
var r;
if(typeof id === 'number'){
products.list.forEach(function(e,i){ if(e.id==id) r= products.list[i];});
} else {
products.list.forEach(function(e,i){ if(e.name==id) r = products.list[i];});
}
return r;
},
list : []
};
var order={
set : function(p) {
order.list[p.id]=p;
},
get : function(id) {
return order.list[id];
},
delete : function(id) {
return delete order.list[id];
},
list : {}
};
then you can do this
products.set('apple',34);
products.set('orange',4);
products.set('mango',1);
var x = products.get(1);
var y = products.get('orange');
order.set(x);
order.set(y);
working demo:
http://jsfiddle.net/techsin/tjDVv/2/

Do I have to initialize every level of an object in Javascript?

I'm not terribly good with Javascript so I'm wondering if there is a better way of doing this:
if (games[level] === undefined) {
games[level] = {};
games[level]['pending'] = {};
}
if (!games[level]['pending'].length) {
return game.create(level);
}
In PHP I can just test empty($games[$level]['pending']). Is there a better way of testing for this? Basically all I want to do is create the object if it does not exist.
if (games[level] === undefined) {
games[level] = game.create(level);
}
If there is no such level game create should be called to initialize all of the data needed. I don`t see any point of making it an object and then checking for "pending". It will be always empty, because you just created the object.
If your the second if returns something for games[level]['pending'].length you have a big problem with your code. You can`t create an empty object ( games[level]['pending'] = {} ) and find that it already has properties.
In addition:
games[level] = {};
// games[level]['pending'] = {}; - bad
games[level].pending = {}; // this way object properties should be used
you can make yourself a function to do that, pass it the games object a a string like "level.pending.id.something.something" and goes on and creates the objects.
function makeObj(obj, path) {
var parts = path.split("."), tmp = obj, name;
while (parts.length) {
name = parts.shift();
if (typeof tmp[name] === 'undefined') {
tmp[name] = {};
}
tmp = tmp[name];
}
}
var x = {};
makeObj(x, "this.is.a.test");
games[level] = games[level] || {pending: {}};
if (!games[level].pending.length) {
return game.create(level);
}

Categories

Resources