On object parameter is not properly set in JavaScript - javascript

I have the following code in my website:
function GroupObject(GroupID, GroupColor, GroupName, CalendarID, UserEnable, IrcChannel) {
this.uid = GroupID;
this.color = GroupColor;
this.groupname = GroupName;
this.calendarid = CalendarID;
this.userenable = UserEnable;
this.ircchannel = IrcChannel;
}
function GetGroupObjects(callback) {
var GlobalDB = [];
$.getJSON("Some Data From Google Docs",
function (data) {
$.each(data.feed.entry, function (i, entry) {
GlobalDB.push(new GroupObject(entry.gsx$uid.$t,
"000000",
SanitizeInputText(entry.gsx$group.$t),
SanitizeInputCalID(entry.gsx$calendarid.$t),
true,
SanitizeInputText(entry.gsx$ircchannel.$t)))
});
console.log(GlobalDB[0]);
console.log(GlobalDB[0].color);
callback(GlobalDB);
});
};
All the parameters of the newly created GlobalDB are correct with the only exception of the parameter "color". console.log(GlobalDB[0]) returns:
GroupObject
calendarid: "CalOfTNG"
color: "AB8B00"
groupname: "Austin TNG"
ircchannel: "AustinTNG"
uid: "TNG"
userenable: true
__proto__: GroupObject
It brings the same value for color "AB8B00" in both Chrome and Firefox. Any idea why? From the code above it should be 0. console.log(GlobalDB[0].color) does returns 000000. But when
I use GlobalDB when returning from the callback I get again AB8B00.
user enable, on the other hand works just fine. I just cannot find what is causignt he problem with the parameter .color as it fails in both Chrome and Firefox.
Thanks in advance.

You seem to be subject to a console.log problem I have experienced often: you don't see the object exactly as it is when logged but as it is later, because the browser doesn't deep clone it immediately when you log but just stores its reference.
This effect doesn't affect primitive, like strings, that's why the color appears initially fine when you log GlobalDB[0].color.
The color is "000000" when you log it. It changes after, probably when you call callback(GlobalDB).
See also this related question (and answer).

Related

Can't change object property for Vue component (a true anomaly)

A strange anomaly. An object/component property this.gridTiles does get set correctly when I do the "undo" action first. But then when I perform the "redo" action (see code below), I'm unable to set this.gridTiles to the new value! It seems to be holding on to the old value. this.gridTiles is an array with nested items/objects. Right before I try to set the value though, it's giving me the correct value if I assign it to a test variable. Very strange! Any help would be much appreciated!
Note : cloneDeep() is enabled by this package : [https://www.npmjs.com/package/clone-deep]
ComponentA.vue
data() {
return {
gridTiles: [],
}
},
....
setCurrentEntireState(historyParams) {
let test = cloneDeep(historyParams.gridTiles); // CORRECT VALUE
this.test = cloneDeep(historyParams.gridTiles); // we can set this arbitrary object property correctly
//this.gridTiles = test; // doesn't work
//delete this.gridTiles; // doesn't help even if we do this first
this.gridTiles = cloneDeep(historyParams.gridTiles); // WRONG VALUE, WHY ??
},
getCurrentEntireState() { // used in saving historyStack items, not shown
return {
gridTiles: cloneDeep(this.gridTiles)
}
},
....
EventBus.$on('refreshHistoryStateForReceiptMap', (historyParams) => {
this.setCurrentEntireState(historyParams);
....
})
ComponentB.vue
methods: {
....
undoHistoryAction() {
let historyParams = this.$store.getters.historyStack[this.$store.getters.historyIndex - 1];
EventBus.$emit('refreshHistoryStateForReceiptMap', historyParams);
this.$store.commit('historyIndexDecrement');
},
redoHistoryAction() {
let historyParams = this.$store.getters.historyStack[this.$store.getters.historyIndex];
EventBus.$emit('refreshHistoryStateForReceiptMap', historyParams);
this.$store.commit('historyIndexIncrement');
}
},
This may not be the correct answer and should maybe be a comment, but is too long to be a comment so I'll post here. Hopes this helps:
The code:
setCurrentEntireState(historyParams) {
let test = cloneDeep(historyParams.gridTiles); // CORRECT VALUE
this.test = cloneDeep(historyParams.gridTiles); // we can set this arbitrary object property correctly
//this.gridTiles = test; // doesn't work
//delete this.gridTiles; // doesn't help even if we do this first
this.gridTiles = cloneDeep(historyParams.gridTiles); // WRONG VALUE, WHY ??
},
gets wrong every line that uses this. I would bet that this code:
EventBus.$on('refreshHistoryStateForReceiptMap', (historyParams) => {
this.setCurrentEntireState(historyParams);
....
})
Is somehow messing with the this context. Maybe is placed inside a callback so it loses the this context of the component?
You should log this inside setCurrentEntireState to check if it really is the component.
The console.log() was showing a different value than when I actually used the Chrome JS debugger with a breakpoint. Also, I investigated further downstream and found that some other custom code was reverting the value back to the old/original one. The moral of the story, console.log() might not always be correct, or there might be some lag?

I can't seem to clear out my localStorage

I can't seem to get my localStorage to clear out
I have two seperate JS files, one is called StorageBin and the other is just called JAS2.
This is my code in the StorageBin
function MyStorage() { };
MyStorage.Keys = {
MyNewObject:""
};
MyStorage.Keys = function (value) {
localStorage.setItem(this.Keys.MyNewObject, JSON.stringify(value))
return value;
};
in the JAS2 file is
$(document).ready(function () {
var myObject = {
Name: "John",
LastName: "Doe"
}
MyStorage.Keys.MyNewObject = myObject;
var hereItIs = MyStorage.Keys.MyNewObject;
console.log(hereItIs.LastName + ", " + hereItIs.Name);
$('#btn').click(function () {
//localStorage.removeItem("MyNewObject");
//localStorage.removeItem("MyStorage.Keys.MyNewObject");
//window.localStorage.clear();
//window.localStorage.removeItem("MyNewObject");
});
$('#btn2').click(function () {
var hereItIs = MyStorage.Keys.MyNewObject;
console.log(hereItIs.LastName + ", " + hereItIs.Name);
});
});
everything you see commented out in the btn click event is everything I have tried. None have worked, I know this because of my btn2 click event.
Where have I went wrong?
Short answer
You’re setting an entry with an object as a key, rather than a string. The resulting key name will be "[object Object]", so you can’t access or delete it with "MyNewObject" or "MyStorage.Keys.MyNewObject".
First problem I noticed: MyStorage.Keys can’t be an object and a function simultaneously. So this code doesn’t make much sense:
MyStorage.Keys = { // This object will be lost shortly.
MyNewObject: ""
};
MyStorage.Keys = function(value){
localStorage.setItem(this.Keys.MyNewObject, JSON.stringify(value))
return value;
};
The first assignment can be removed.
Of course, a new MyNewObject property will exist after this line:
MyStorage.Keys.MyNewObject = myObject;
In the saving function (MyStorage.Keys), you’re setting a LocalStorage entry with the key this.Keys.MyNewObject. It refers to myObject, which is an object. This also doesn’t make sense, because setItem expects a string as the first argument, not an object. The argument will therefore be cast to a string and result in [object Object].
It appears, however, that you want to access your LocalStorage entry with either "MyNewObject" or "MyStorage.Keys.MyNewObject". So just set it with one of these lines instead:
localStorage.setItem("MyNewObject", JSON.stringify(value));
localStorage.setItem("MyStorage.Keys.MyNewObject", JSON.stringify(value));
Then one of your two first attempts or the last one will work.
If you want the key to be {Name:"John",LastName:"Doe"}, use
localStorage.setItem(JSON.stringify(this.Keys.MyNewObject), JSON.stringify(value));
If you want the key to be Doe, John, use
localStorage.setItem(hereItIs.LastName + ", " + hereItIs.Name, JSON.stringify(value));
In any case, if you want to remove those entries, you need to generate its key the same way.
localStorage.clear(); should also clear everything from local storage. I can’t reproduce it not working.
Debugging
You can debug the Local Storage by using the browser console (dev tools) (hit F12) and going to the Storage tab (you may need to enable it in the dev tools settings). There you will see which keys and values are saved.
Further examples
Storage on MDN
Setting an entry
localStorage.setItem("MyNewObject", JSON.stringify(value));
Getting that entry
localStorage.getItem("MyNewObject");
Deleting that entry
localStorage.removeItem("MyNewObject");

Mongoose/MongoDB result fields appear undefined in Javascript

Is there something that I'm missing that would allow item to log as an object with a parameter, but when I try to access that parameter, it's undefined?
What I've tried so far:
console.log(item) => { title: "foo", content: "bar" } , that's fine
console.log(typeof item) => object
console.log(item.title) => "undefined"
I'll include some of the context just in case it's relevant to the problem.
var TextController = function(myCollection) {
this.myCollection = myCollection
}
TextController.prototype.list = function(req, res, next) {
this.myCollection.find({}).exec(function(err, doc) {
var set = new Set([])
doc.forEach(function(item) {
console.log(item) // Here item shows the parameter
console.log(item.title) // "undefined"
set.add(item.title)
})
res.json(set.get());
})
}
Based on suggestion I dropped debugger before this line to check what item actually is via the node repl debugger. This is what I found : http://hastebin.com/qatireweni.sm
From this I tried console.log(item._doc.title) and it works just fine.. So, this seems more like a mongoose question now than anything.
There are questions similar to this, but they seem to be related to 'this' accessing of objects or they're trying to get the object outside the scope of the function. In this case, I don't think I'm doing either of those, but inform me if I'm wrong. Thanks
Solution
You can call the toObject method in order to access the fields. For example:
var itemObject = item.toObject();
console.log(itemObject.title); // "foo"
Why
As you point out that the real fields are stored in the _doc field of the document.
But why console.log(item) => { title: "foo", content: "bar" }?
From the source code of mongoose(document.js), we can find that the toString method of Document call the toObject method. So console.log will show fields 'correctly'. The source code is shown below:
var inspect = require('util').inspect;
...
/**
* Helper for console.log
*
* #api public
*/
Document.prototype.inspect = function(options) {
var isPOJO = options &&
utils.getFunctionName(options.constructor) === 'Object';
var opts;
if (isPOJO) {
opts = options;
} else if (this.schema.options.toObject) {
opts = clone(this.schema.options.toObject);
} else {
opts = {};
}
opts.minimize = false;
opts.retainKeyOrder = true;
return this.toObject(opts);
};
/**
* Helper for console.log
*
* #api public
* #method toString
*/
Document.prototype.toString = function() {
return inspect(this.inspect());
};
Make sure that you have defined title in your schema:
var MyCollectionSchema = new mongoose.Schema({
_id: String,
title: String
});
Try performing a for in loop over item and see if you can access values.
for (var k in item) {
console.log(item[k]);
}
If it works, it would mean your keys have some non-printable characters or something like this.
From what you said in the comments, it looks like somehow item is an instance of a String primitive wrapper.
E.g.
var s = new String('test');
typeof s; //object
s instanceof String; //true
To verify this theory, try this:
eval('(' + item + ')').title;
It could also be that item is an object that has a toString method that displays what you see.
EDIT: To identify these issues quickly, you can use console.dir instead of console.log, since it display an interactive list of the object properties. You can also but a breakpoint and add a watch.
Use findOne() instead of find().
The find() method returns an array of values, even if you have only one possible result, you'll need to use item[0] to get it.
The findOne method returns one object or none, then you'll be able to access its properties with no issues.
Old question, but since I had a problem with this too, I'll answer it.
This probably happened because you're using find() instead of findOne(). So in the end, you're calling a method for an array of documents instead of a document, resulting in finding an array and not a single document. Using findOne() will let you get access the object normally.
A better way to tackle an issue like this is using doc.toObject() like this
doc.toObject({ getters: true })
other options include:
getters: apply all getters (path and virtual getters)
virtuals: apply virtual getters (can override getters option)
minimize: remove empty objects (defaults to true)
transform: a transform function to apply to the resulting document before returning
depopulate: depopulate any populated paths, replacing them with their original refs (defaults to false)
versionKey: whether to include the version key (defaults to true)
so for example you can say
Model.findOne().exec((err, doc) => {
if (!err) {
doc.toObject({ getters: true })
console.log('doc _id:', doc._id) // or title
}
})
and now it will work
You don't have whitespace or funny characters in ' title', do you? They can be defined if you've quoted identifiers into the object/map definition. For example:
var problem = {
' title': 'Foo',
'content': 'Bar'
};
That might cause console.log(item) to display similar to what you're expecting, but cause your undefined problem when you access the title property without it's preceding space.
I think using 'find' method returns an array of Documents.I tried this and I was able to print the title
for (var i = 0; i < doc.length; i++) {
console.log("iteration " + i);
console.log('ID:' + docs[i]._id);
console.log(docs[i].title);
}
If you only want to get the info without all mongoose benefits, save i.e., you can use .lean() in your query. It will get your info quicker and you'll can use it as an object directly.
https://mongoosejs.com/docs/api.html#query_Query-lean
As says in docs, this is the best to read-only scenarios.
Are you initializing your object?
function MyObject()
{
this.Title = "";
this.Content = "";
}
var myo1 = new MyObject();
If you do not initialize or have not set a title. You will get undefined.
When you make tue query, use .lean() E.g
const order = await Order.findId("84578437").lean()
find returns an array of object , so to access element use indexing, like
doc[0].title

chrome.storage.sync.set not saving values

So I've run into a bit of snag with regards to local storage on Google Chrome. From what I've researched, my syntax seems to be correct, but for some reason the value is not being saved. Here's my code:
chrome.storage.sync.get(accName, function(data) {
var accData = data[accName];
// Stuff
chrome.storage.sync.set({ accName: accData }, function() {
alert('Data saved');
});
});
Every time I re-run it, data[accName] returns undefined. I've tried the same code with literal values for the sync.set parameters (eg. { 'john32': ['fk35kd'] }), and that seems to work, so I'm really confused as to what the issue could be. Any help would be appreciated.
The issue was trying to plug accName into an object literal inside the set statement (credit to Rob above). What I'd end up with was an object with a property 'accName' rather than the value of accName itself. Here's a fix.
var obj = {};
obj[accName] = accData;
chrome.storage.sync.set(obj, function() {
alert('Data saved');
});
Update
ES6 now allows computed property names in object literals, so the above can be achieved with:
chrome.storage.sync.set({ [accName]: accData }, function() {
alert('Data saved');
});

How to get input from Chrome's Javascript console?

Is there a way to programmatically get input from the Javascript Console of Google Chrome, similar to readline() in Firefox?
A tricky way to do this is assigning a getter to a property of a window object
Object.defineProperty(window, 'customCommand', {
get: function() {
console.log("hey");
return "hey";
}
});
So when you type "customCommand" (without parenthesis) it will print your console.log text to the console while the console is "getting" the variable.
You will still have to return something though, and I'm not sure how you could change the order so that the value is returned first and the text in the console appears second. It's definitely possible though, I've seen this happen.
This is an indirect method of taking inputs:
Declare a function in JavaScript:
function your_command_here() {
//code
}
As Chrome's console basically provides methods for communicating with the page's contents, like JavaScript variables, functions, etc., so declaring a function as a receivable command can be an option.
In the console, for providing input, the user shall type:
your_command_here()
Another workaround is:
Declare a function:
function command(var cmnd) {
switch(cmnd) {
case "command1":
//code
break;
}
}
So the user can (more conveniently) type:
command("user's command here")
We can do is hook the console.log so whenever it logs something we can access, otherwise there is no such direct method as like in firefox which does this possible for us in a simple single line code.
var tempStore = [];
var oldLog = console.log;
console.log = function() {
tempStore.push(arguments);
oldLog.apply(console, arguments);
}
You might need to incorporate jsh (Javascript Shell) in your environment if you are working with console IO. See http://code.google.com/p/jsh/ for the how-to. Hope this helps.
Sorry, doesn't work on Chrome JS Console, just works on the repl from repl.it
Example from repl.it:
console.log("Enter your name:");
console.read(function(name) {
console.log('Your name is ' + name + '.');
});
Here is a solution to input from the console.
Try this out!!
process.stdin.resume();
process.stdin.setEncoding('ascii');
var stdInput = "";
var stdInputArr = "";
var index = 0;
process.stdin.on('data', function (data) {
stdInput += data;
});
process.stdin.on('end', function () {
stdInputArr = stdInput.split("\n");
main();
});
// Reads complete line from STDIN
function readLine() {
return stdInputArr[index++];
}
//call this function in the main function
javascript node.js jquery consoleweb
The better you can do is use:
myVar = prompt('Which value do your want?')

Categories

Resources