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");
Related
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 would like to capture user's input through browser's console.
Currently I get input using JS's prompt, like so:
var a = prompt("Enter your numbers").split(",");
console.log(a);
But I would like data to be entered through the console.
Is there a way to do this with Javascript or Typescript?
EDIT
John Weisz gave good answer, this would normally work, it won't work with my problem.
You see, the user will use the console to enter a string of numbers which I will store into an array and check for duplicates...
Then print those duplicates with an object to the console...
var a;
window.cliApi = {
setValue: function (value) {
a = value;
}
}
var counts = {};
a.forEach(function(x){
counts[x] = (counts[x] || 0) +1; });
console.log(counts);
Sort of. You can create a globally exposed API that the user can use from the console, for example:
var a;
window.cliApi = {
setValue: function (value) {
a = value;
},
getValue: function () {
return a;
}
}
Then, in the browser console, you can type:
cliApi.setValue("hello world")
After which your variable will be populated.
Fiddle here.
Note, that with JSFiddle, you will need to set the console scope to the result frame instead of top (you do this inside your dev tools), as your code is running inside a frame. This is not required if you host your code yourself (and not from a frame).
I'm debugging a complex JS client side framework based on Ext. I stumbled upon a line that gives results that I fail to explain in any way. Here is the line (me is actually just an alias for this):
me.displayTplData = displayTplData;
Some values before executing it:
me.value: "87172981"
displayTplData: Array[1] (this is a local variable)
me.displayTplData: undefined
After the line (F11, "step into next function call"):
me.value: null
displayTplData: Array[1] (stays as before)
me.displayTplData: null
Not only the assignment apparently didn't happen, this also altered value assigned to an unrelated attribute value... The only way I could think of is if displayTplData has an associated setter (similar to descriptors in Python?). But on the other hand, JS debugger doesn't step into any code when executing the line. Also, this framework works on IE8+, so it certainly doesn't use any recent JS developments.
This happens both with FireFox and Chrome, so it must be some "this is supposed to work this way", but I completely don't understand what's going on.
Can someone guess what might be the reason of it? Sorry, I cannot reduce it to a standalone example.
EDIT:
Here is the full function, as a context.
setValue: function(value, doSelect) {
var me = this,
valueNotFoundText = me.valueNotFoundText,
inputEl = me.inputEl,
i, len, record,
dataObj,
matchedRecords = [],
displayTplData = [],
processedValue = [];
if (me.store.loading) {
// Called while the Store is loading. Ensure it is processed by the onLoad method.
me.value = value;
me.setHiddenValue(me.value);
return me;
}
// This method processes multi-values, so ensure value is an array.
value = Ext.Array.from(value);
// Loop through values, matching each from the Store, and collecting matched records
for (i = 0, len = value.length; i < len; i++) {
record = value[i];
if (!record || !record.isModel) {
record = me.findRecordByValue(record);
}
// record found, select it.
if (record) {
matchedRecords.push(record);
displayTplData.push(record.data);
processedValue.push(record.get(me.valueField));
}
// record was not found, this could happen because
// store is not loaded or they set a value not in the store
else {
// If we are allowing insertion of values not represented in the Store, then push the value and
// create a fake record data object to push as a display value for use by the displayTpl
if (!me.forceSelection) {
processedValue.push(value[i]);
dataObj = {};
dataObj[me.displayField] = value[i];
displayTplData.push(dataObj);
// TODO: Add config to create new records on selection of a value that has no match in the Store
}
// Else, if valueNotFoundText is defined, display it, otherwise display nothing for this value
else if (Ext.isDefined(valueNotFoundText)) {
displayTplData.push(valueNotFoundText);
}
}
}
// Set the value of this field. If we are multiselecting, then that is an array.
me.setHiddenValue(processedValue);
me.value = me.multiSelect ? processedValue : processedValue[0];
if (!Ext.isDefined(me.value)) {
me.value = null;
}
me.displayTplData = displayTplData; //store for getDisplayValue method <------- this is the line
me.lastSelection = me.valueModels = matchedRecords;
if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
inputEl.removeCls(me.emptyCls);
}
// Calculate raw value from the collection of Model data
me.setRawValue(me.getDisplayValue());
me.checkChange();
if (doSelect !== false) {
me.syncSelection();
}
me.applyEmptyText();
return me;
},
Sometimes the debugger provides false information. It is strange that both Firefox's and Chrome's debugger produces the same (wrong) inspection, but if you want to be sure about those values, just put console.log(me.value) before and after the statement, and see what gets printed.
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
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).