I have the following code:
exports.home = function(Comment,User,Activity){
return function(req, res){
var get_url = req.url.split(/\?/)[1];
if (!req.user)
{
res.writeHead(302, {
'Location': '/'
});
res.end();
return;
}
var posts_id_array = req.user.posts_id_array;
var stocks_array = req.user.watch_list;
var subscribe_to_arr = req.user.subscribe_to;
User.find({_id:{$ne:req.user._id, $nin:subscribe_to_arr}}).sort('-_id').limit(10).exec(function(err_user, users){
Activity.find({$or:[{owner_id : {$in :subscribe_to_arr}},{owner_id:req.user._id}]}).sort('-time_stamp').limit(20).exec(function(err_post,activities){
if( err_post || !activities) {
res.render('home',{user:req.user,stocks:JSON.stringify(stocks_array)});
}
else
{
var funcArr = [];
var hasPost = ["publish","comment","like"];
var notPost = ["add_stock","delete_stock"];
for(var i =0;i<activities.length;i++)
{
if(hasPost.indexOf(activities[i].type)!=-1){
var fobj = {
act: activities[i],
f:function(callback){
var test = this.act;
var comments = test.post.comments;
Comment.find({_id:{$in:comments}},function(err,_comments){
console.log("test.post.comments");
//console.log(test.post.comments);
console.log("comments ");
console.log(_comments);
console.log("type");
console.log(typeof test);
console.log("cloning obj");
// obj = JSON.parse(JSON.stringify(test)); // cloning obj
console.log(test);
console.log("setting value of comments");
**console.log(test.post.comments = _comments);** //unable to change test.post.comments
console.log("after assignment");
console.log(test.post.comments); // remain unchanged but work with obj.post.comments if I clone test as obj and use obj instead.
callback(null,test);
});
}
}
funcArr.push(fobj.f.bind(fobj));
}else{
var fobj = {
act: activities[i],
f :function(callback){
callback(null,this.act);
}
}
funcArr.push(fobj.f.bind(fobj));
}
}
async.series(funcArr,function(err,resArr){
console.log("resArr");
console.log(resArr);
res.render('home',{user:req.user,posts:JSON.stringify(resArr),stocks:JSON.stringify(stocks_array), other_users:JSON.stringify(users)});
});
}
});
}) // end of User.find
}// end of return function(req,res);
}
I want to update the post.comments property of the "test" object (see ** parts), but I was unable to do so. However, when I cloned the "test" object as "obj" then set "obj.post.comments" it works. Why is it the case? Is it because I messed up some scoping issues?
Thanks.
I have solved this problem myself. It turns out that I have store mongodb's Schema.Types.ObjectId in the test.post.comments which after some messing around I found cannot be overwritten. When I create a clone of the test object as "obj", the Schema.Types.ObjectId object in obj.post.comments is stored at a different location which allows for modification. My conjecture is that test.post.comments points to a Schema.Types.ObjectId within mongodb itself and therefore cannot be overwritten. When I create a copy of the test object, the problem is therefore resolved.
var test = this.act.concat();
use this instead.
because arrays substitution in js actually does not copy array but refer original adresses.
for example
var test = ['A','B','C','D'];
var copied = test;
test[0] = 0;
copied[1] = 0;
console.log(test) //0,0,'C','D'
console.log(copied) //0,0,'C','D'
so to avoid this issue, You can use .concat() to copy array
if you do not add anything, it will be used as copying.
var test = ['A','B','C','D'];
var copied = test.concat();
test[0] = 0;
copied[1] = 0;
console.log(test) //0,'B','C','D'
console.log(copied) //'A',0,'C','D'
Related
Thanks in advance for any responses:
I don't think this is a duplicate: I reviewed that article in the first comment, that is just a general breakdown of objects and using "this" within javascript.
My other this.function's perform just fine, so I at least have the basics of JS Obj's figured out.
This issue is related to using .map() with a this.function within a constructed object.
The following Google Appscript code uses .map() to update a string in a 2d array. [[string, int],[string, int]]
For some reason, when using .map() it is am unable to access the function "this.removeLeadingZero". If that same function is placed outside of the OBJ it can be called and everything works just fine. For some reason the system claims row[0] is an [object, Object] but when I typeof(row[0]) it returns "string" as it should.
Error: TypeError: Cannot find function removeLeadingZero in object [object Object]. (line 106, file "DEEP UPC MATCH")
Is there any issue using this.function's with .map() inside an object or am I using an incorrect syntax?
function test2DMapping(){
var tool = new WorkingMappingExample()
var boot = tool.arrayBuild();
Logger.log(boot)
}
function WorkingMappingExample(){
this.arr= [["01234", 100],["401234", 101],["012340", 13],["01234", 0422141],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3]];
//mapping appears faster that normal iterations
this.arrayBuild = function(){
var newArray1 =
this.arr.map( function( row ) {
**var mUPC = removeLeadingZero2(row[0])** //working
**var mUPC = this.removeLeadingZero(row[0])** // not working
var index = row[1]
Logger.log(mUPC + " " + index)
row = [mUPC, index]
return row
} )
return newArray1;
};
}; //end of OBJ
//THE NEXT 2 FUNCTIONS ARE WORKING OUTSIDE OF THE OBJECT
function removeLeadingZero2(upc){
try {
if (typeof(upc[0]) == "string"){
return upc.replace(/^0+/, '')
} else {
var stringer = upc.toString();
return stringer.replace(/^0+/, '')
}
} catch (err) {
Logger.log(err);
return upc;
}
}
function trimFirstTwoLastOne (upc) {
try {
return upc.substring(2, upc.length - 1); //takes off the first 2 #'s off and the last 1 #'s
} catch (err) {
Logger.log(err);
return upc;
}
}
Inside the function that you pass to map, this doesn't refer to what you think it does. The mapping function has its own this, which refers to window, normally:
var newArray1 = this.arr.map(function(row) {
// this === window
var mUPC = this.removeLeadingZero(row[0]);
var index = row[1];
Logger.log(mUPC + " " + index);
return [mUPC, index];
});
You have four options:
Array#map takes a thisArg which you can use to tell map what the this object in the function should be:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}, this); // pass a thisArg
Manually bind the function:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}.bind(this)); // bind the function to this
Store a reference to the outer this:
var self = this;
var newArray1 = this.arr.map(function(row) {
// self === (outer this)
var mUPC = self.removeLeadingZero(row[0]);
// ...
});
Use an arrow function:
var newArray1 = this.arr.map(row => {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
});
Additionally, you could stop using this and new.
I have solved this issue and below is the answer in case anyone else runs into this:
this needs to be placed into a variable:
var _this = this;
and then you can call it within the object:
var mUPC = _this.removeLeadingZero(row[0])
Javascript scope strikes again!
The following code gives me the error "Cannot read property PERSON1 of null". If I comment out the line where I try to assign the dynamic variable and uncomment the alert line it pops up alerts with each successive person's name.
function fillInternalRepData() {
var internalRepList = null;
console.log("Querying Table for internal reps");
queryTable(//..blabla..//, "false", function (callbackResp) {
internalRepList = callbackResp;
// alert("TRIGGERED"); //WORKS
// alert(internalRepList.length); //WORKS
angular.forEach(internalRepList, function (rep) {
repName = rep.such;
$scope.internalReps[repName].such = repName;
//alert(repName); //WORKS WHEN LINE ABOVE IS COMMENTED OUT
});
}); //get list of internal reps
I simply want to create/add to the $scope.internalReps object so that I can add stuff to it like $scope.internalReps.PERSON1.Name = "Whatever"; $scope.internalReps.PERSON1.Salary = 100000;
Try adding an empty object for the "internalReps" before your forEach loop. It doesn't look like you've declared the object yet, so it can't dynamically add to a null object.
$scope.internalReps = {};
angular.forEach(internalRepList, function (rep) {
repName = rep.such;
$scope.internalReps[repName] = {};
$scope.internalReps[repName].such = repName;
//alert(repName);
});
var internalReps = {};
angular.forEach(internalRepList, function (rep) {
repName = rep.such;
internalReps[repName] = { such: "" };
internalReps[repName].such = repName;
//alert(internalReps[repName].such);
});
That worked. Thanks for the help!
I am writing a simple application in node, but having trouble with referencing objects from different modules. The object constructor and methods are (I skipped some methods to keep the excerpt short):
function Account (name, password) {
this._name = name;
this._password = password;
this._attributes = [];
}
Account.prototype.load = function (id) {
var self = this;
self = db.loadObject(id, 'account'); // separate module to save/retrieve data
this._name = self._name;
this._password = self._password;
this._attributes = self._attributes;
return this;
};
Account.prototype.getAttributes = function () {
return this._attributes;
}
Account.prototype.addAttributes = function (a) {
this._attributes.push(a);
};
module.exports = Account;
The db module is nothing fancy at this point:
var fs = require('fs');
var paths = {
'account' : './data/accounts/'
};
function loadObject (name, type) {
var filePath = paths[type] + name + '.json';
if (!fs.existsSync(filePath)) {
return false;
}
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
};
function saveObject (object, type) {
fs.writeFileSync(paths[type] + object.getName() + '.json', JSON.stringify(object),'utf8');
};
exports.loadObject = loadObject;
exports.saveObject = saveObject;
The file is saved as:
{"_name":"John","_password":"1234","_attributes":[["Jane","sub",[[10,1]]]]}
On my caller module I attempt to retrieve the attributes:
var Account = require('./account.js');
var account = new Account();
...
account.load(name);
...
var attr = account.getAttributes();
for (var item in attr) {
console.log(item[0]);
};
...
In the code above, the last loop prints undefined objects. I have checked the files and the information is saved and loaded without any problems. The array attr is not empty. If I print it with:
util.log(typeof attr+': '+attr);
I get:
object: Jane,sub,10,1
Instance issue? Should I rewrite the _attributes to be accessed directly via account.attributes?
This is the code you currently have for outputting your data:
var attr = account.getAttributes();
for (var item in attr) {
console.log(item[0]);
};
What this code does is output to the console the first character of each key in your _attributes field. With the data you've shown in your question, what this outputs is 0 because your _attributes field has this value: [["Jane","sub",[[10,1]]]]. When used in var item in attr the item variable will get only one value the string "0", and item[0] will also evaluate to the string "0". I've actually cut and pasted your code and data into files and ran your code to double check this and this is indeed what I get when I run the code. I don't get undefined values. A more sensible way to get the values out of the array would be:
var attr = account.getAttributes();
for (var item in attr) {
console.log(attr[item]);
}
If you want to iterate two levels deep:
for (var item in attr) {
var value = attr[item];
for (var item2 in value) {
console.log(value[item2]);
}
}
Here is the code:
http://jsfiddle.net/GKBfL/
I am trying to get collection.prototype.add to return a reference such that the final alert will display testing, testing, 123, testing. Is there a way to accomplish what I'm trying to do here?
HTML:
<span id="spantest">testing, testing, 123, testing</span>
JavaScript:
var collection = function () {
this.items = {};
}
collection.prototype.add = function(sElmtId) {
this.items[sElmtId] = {};
return this.items[sElmtId];
}
collection.prototype.bind = function() {
for (var sElmtId in this.items) {
this.items[sElmtId] = document.getElementById(sElmtId);
}
}
var col = new collection();
var obj = {};
obj = col.add('spantest');
col.bind();
alert(obj.innerHTML);
You problem is this line:
this.items[sElmtId] = document.getElementById(sElmtId);
This overwrites the object currently assigned to this.items[sElmtId] with the DOM node. Instead, you should assign the node to a property of that object:
this.items[sElmtId].node = document.getElementById(sElmtId);
That way, obj.node will always refer to the current node:
alert(obj.node.innerHTML);
DEMO
Side note: The problem with your fiddle is also that you execute the code when the DOM is not built yet (no wrap (head)), so it cannot find #spantest. You have to run the code once the DOM is ready, either no wrap (body), onDomRead or onLoad.
Creating a reference like you need is impossible in JavaScript. The closest thing you can get is either a nested or closed object, or just copying it over, like so:
var collection = function() {
this.items = {};
};
collection.prototype.add = function(sElmtId) {
return this.items[sElmtId] = {};
};
collection.prototype.bind = function() {
for(var sElmtId in this.items) {
var element = document.getElementById(sElmtId);
for(var x in element) {
this.items[sElmtId][x] = element[x];
}
}
};
var col = new collection();
var obj = {};
obj = col.add('spantest');
col.bind();
alert(obj.innerHTML);
But it won't be truly "bound". You'll have to use nested objects if you need that kind of functionality, and it will probably defeat the point of your syntactic sugar.
http://jsfiddle.net/GKBfL/7/
Noob question. Setting array elements throws an error.
I get this error when I run the script: array1[user_id] is undefined.
array1 = new Array();
// the data variable I got from a JSON source
// using jQuery
$.each(data, function(i, item) {
// Set variables
user_id = item.post.user_id;
user = item.post.user;
price = item.post.price;
if (array1[user_id]['user'] != user) {
array1[user_id]['price'] = price;
array1[user_id]['user'] = user;
}
}
First, you should not use an array, if you need a hash map, use objects. In some languages, it's one thing, but in JS they're not.
When defining a nested object you have to define each level as an object.
var hash = {};
// the data variable I got from a JSON source
$.each(data, function(i, item) {
// Set variables
user_id = item.post.user_id;
user = item.post.user;
price = item.post.price;
// Have to define the nested object
if ( !hash[user_id] ) {
hash[user_id] = {};
}
if (hash[user_id]['user'] != user) {
hash[user_id]['price'] = price;
hash[user_id]['user'] = user;
}
}
If I understand this question correctly, you have to initialize the first dimension of array1 first, like so:
array1[user_id] = {};
then you can do this:
array1[user_id]['user'] = 'whatever';
That is of course assuming your user_id is not undefined.