How to set Key/Value pair to chrome.storage.sync - javascript

I am trying something simple with a Chrome Extension, but the documentation I have found is not clear enough regarding the structure of the methods to use the chrome storage. I have the following code (generic) to store and retrieve some values:
var value = 561;
var key = "abc";
chrome.storage.sync.set({ [key] : value });
chrome.storage.sync.get(key, ({ result }) => {
console.log("value received is: " + result); // This does not work, result = undefined
});
If I want to retrieve the key added to the store, what is wrong with the previous code?

When using { result } you are extracting result from the first parameter being passed.
Should be instead:
var value = 561;
var key = "abc";
chrome.storage.sync.set({[key]: value });
chrome.storage.sync.get(key, ({ abc }) => {
console.log("value received is: " + abc);
});
// or
chrome.storage.sync.get(key, (result) => {
console.log("value received is: " + result.abc);
});
TLDR;
In JavaScript, when adding { result } you are extracting that variable from the underlying object in this case, the parameter.
Assuming the object is:
const results = {
a: 1,
b: 2,
c: 3
}
You can simplify the parameters to be like:
const { a, b ,c } = results
which is similar to:
const a = results.a
const b = results.b
const c = results.c
Since the first argument in your function is now { result }, it is expecting that key to exist in the first argument of that function. But it doesn't, it should be instead{abc}

Related

Firebase Batch set with invalid data

Error Message: Function WriteBatch.set() called with invalid data. Data must be an object, but it was: www.google.com
I have a button that onclick runs the addQuotes function.
Where am I going wrong?
const addQuotes = async () => {
let test = ['https://www.google.com/', 'https://www.google.com/about',]
const obj1 = Object.assign({}, test);
const batch = writeBatch(db);
Object.keys(obj1).forEach(key => {
var docRef = db.collection("col").doc(); //automatically generate unique id
batch.set(docRef, obj1[key]);
});
batch.commit().then(function () {
console.log("hello")
});
}
As the error says, the data param should be an object (second argument to the batch.set method)
Commented out the firebase methods invocation for running the code
and show you the o/p
// In your case when you do
let test = ['https://www.google.com/', 'https://www.google.com/about', ]
const obj1 = Object.assign({}, test);
console.log(obj1);
// and ignoring the unique id step
Object.keys(obj1).forEach((key, index) => {
// var docRef = db.collection("col").doc(); //automatically generate unique id
console.log(obj1[key]); // here it is just the string value
console.log({[index]: obj1[key]}); // here it is an object
//when you do the bellow line
// batch.set(docRef, obj1[key]); // value of obj1[key] is just string which is not the correct type
// may be you do something as below (key can be as you want it to be)
// batch.set(docRef, {[index]: obj1[key]}); // index is added as key for the object which in now an object and should work
});
I used {[index] : obj1[key]} notation which is computed property in object
Hope it's clear 🙂

Storing a dynamic list using chrome.storage.sync.set() for a Chrome extension

I am trying to store an object, mapping a string to a list, using chrome.sync.get. My goal is to create a new list for a non-existing key or append an element to the list if the key exists. However, I am unable to populate the object. When I try to retrieve the values I have previously inserted, I get an empty Object as the returned value. Following is the code I am using:
let currentTabId = '234';
let spawnedTabId = '390';
chrome.storage.sync.get(currentTabId, function(data) {
if (typeof data.currentTabId === 'undefined') {
chrome.storage.sync.set({currentTabId: [spawnedTabId]}, function() {
console.log("Initialized "+currentTabId+" with "+spawnedTabId);
});
chrome.storage.sync.get(currentTabId, function(data) {
console.log(data);
});
} else {
data.currentTabId.push(spawnedTabId)
chrome.storage.sync.set({currentTabId: data.currentTabId}, function() {
console.log("Appended "+spawnedTabId+" to "+currentTabId);
});
}
});
The output I am getting is:
>>> Initialized 234 with 390
>>> {}
__proto__: Object
The code had three mistakes:
incorrect use of a variable to make an object literal,
instead of {variable: value} it should be {[variable]: value}, more info
incorrect use of a variable to read a property from an object,
instead of obj.variable it should be obj[variable]
incorrect use of asynchronous API,
the data should be read after it's written i.e. inside the callback.
let key = '234';
let spawnedTabId = '390';
chrome.storage.sync.get(key, data => {
const spawned = data[key] || [];
spawned.push(spawnedTabId);
chrome.storage.sync.set({ [key]: spawned }, () => {
// now you can read the storage:
// chrome.storage.sync.get(key, console.log);
});
});

Object has values but says size is 0 javascript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I create an object and add properties and values to it. However, when I try to iterate through the keys it says I have a size of 0.
let hash = {};
this.props.user.user.following.forEach(async topicId => {
await API.graphql(graphqlOperation(queries.getTopic, {id: topicId})).then(data => {
if(data) {
const tweetId = data.data.getTopic.post.id;
if(!hash[tweetId]){
let post = data.data.getTopic.post;
post.topics = [{
id: data.data.getTopic.id,
name: data.data.getTopic.name
}]
hash[tweetId] = post;
} else {
console.log("Found tweet. Appending to topics array.");
let post = hash[tweetId];
let topicsArr = post.topics;
topicsArr.push({
id: data.data.getTopic.id,
name: data.data.getTopic.name
})
post.topics = topicsArr;
hash[tweetId] = post;
}
}})
});
console.log("Hash: ", hash);
console.log("Map size: ", Object.keys(hash).length);
let tweets = [];
for(var key in hash) {
tweets.push(hash[key]);
}
console.log("Tweets to go into state: ", tweets);
My output is as follows(the array on the last line is empty):
You're adding to the hash object with an async function.
So, each of runs through the forEach are done asynchronously, and the evaluation of the rest of the code continues on. The block where you use the data runs before your asynchronous functions have all completed.
You should have both the code where you fetch and the code where you process data from an API call in the same asynchronous block, since, when you think about it, a block of code can't depend on asynchronous code without itself being asynchronous.
You probably want to await all of the API calls you're doing in that loop. To do so, you can use Array.prototype.map() and Promise.all().
const tweets = async () => {
let hash = {};
await Promise.all(this.props.user.user.following.map(async topicID => {
const data = await API.graphql(graphqlOperation(queries.getTopic, { id: topicID }));
// No need to use .then(), since we're awaiting anyways
if (data) {
const tweedID = data.data.getTopic.post.id;
if (!hash[tweetID]) {
let post = data.data.getTopic.post;
post.topics = [{
id: data.data.getTopic.id,
name: data.data.getTopic.name
}]
hash[tweedID] = post;
} else {
console.log("Found tweet. Appending to topics array.");
let post = hash[tweedID];
let topicsArr = post.topics;
topicsArr.push({
id: data.data.getTopic.id,
name: data.data.getTopic.name
});
post.topics = topicsArr;
hash[tweedID] = post;
}
}
}));
console.log("Hash: ", hash);
console.log("Map size: ", Object.keys(hash).length);
let tweets = [];
for (const key in hash) {
tweets.push(hash[key]);
}
console.log("Tweets to go into state: ", tweets);
}
tweets();
// Or, put the whole thing in brackets and call it immediately:
(async () => {
// ...
})();
The reason that you see that the logged object has values is because of a feature of the dev-console that live-refreshes objects' properties, so they will no longer reflect the state when they've been logged, but instead display their current value.
Consider the following example:
const obj = {};
console.log(obj);
obj.foo = 'bar';
You'll see that the obj's foo property is 'bar', even though it was undefined when console.log was actually run. As #epascarello pointed out in the comments, you can tell when your browser has done this because of the little blue [i]. If you hover over it, you'll see that it says "This value was evaluated just now".
To avoid that behavior, JSON.stringify the object before logging:
const obj = {}
console.log(JSON.stringify(obj))
obj.foo = 'bar'
This will log {}, as you might expect, since it turns it into a string and spits that text out, instead of a reference to obj.
See more here.

JS Array allways returns undefined and length = 0

(using Node.js)
Hi, I have an array with users (User class) on it, when I print the array with console.log, it shows the content correctly and shows that it's length is 3, but when i try to get any thing from the array, it returns undefined and for *.length, it returns 0. Where's the problem?
exports.users = [];
exports.loadUsers = (callback) => {
let more = true;
let i = 0;
while(more) {
let us = _usersFolder + "us_" + i + "/";
if(fs.existsSync(us)) {
fs.readFile(path.join(us + "personal.json"), (err, data) => {
if(err) {
console.log("failed to load file!");
return;
}
let json_personal = JSON.parse(data);
this.users.push(new User(json_personal));
});
i++;
} else {
more = false;
}
}
callback();
}
exports.getUserById = (id) => {
console.log(this.users);
console.log("length: " + this.users.length);
console.log(this.users[0]);
for(let i = 0; i < this.users.length; i++) {
let u = this.users[i];
console.log(u.id);
if(u.id === id) {
return u;
}
}
return false;
}
getUserById is called in the callback, so users are already loaded.
It depends on where you are using the 'this' object. It's possible that 'this' makes reference to a different object than the one you stored the array in ('this' varies depending on the scope where you are using it).
I'd need more information to help you.
var users=[{"num":1},{"num":2},{"num":3}];
console.log(this.users);
console.log("length: " + this.users.length);
console.log(this.users[0]);
output
(3) [Object, Object, Object]
length: 3
Object {a: 1}
I hope you are defining after you print in console.
var users = [];
console.log(users);
console.log("length: " + users.length);
console.log(users[0]);
users.push(1);
users.push(2);
users.push(3);
The output of console.log() is misleading; While you log that time there was no value. After that it was added. It prints the reference of object , not the state value. So you will see current state value all the time.

using json objects in URLSearchParams

Is it possible to somehow append json objects onto a URLSearchParams object?
So instead of:
urlSearchParams.append('search', 'person');
it's:
urlSearchParams.append({search: "person"});
My answer courtesy of Darshak Gajjar's answer
Can use json objects via this way:
let test_this = [{"search": "person"}, { search: "another person"}];
var json = JSON.stringify(test_this);
urlSearchParams.append("myobj", json);
return this.http.post(this.post_url, urlSearchParams, options) //options being your own RequestOptions
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Something like this might work urlSearchParams = Object.assign(urlSearchParams, {search: "person"});
EDIT: Alternate solution using vanilla javascript. Also, I thought URLSearchParams was just a normal js object, but in fact you have to use get, set and append to access properties.
var params = new URLSearchParams("a=apple&b=balloon");
var parametersToAdd = {c: "car", d: "duck"};
for(key in parametersToAdd)
params.append(key, parametersToAdd[key]);
console.log(params.get('c'));
console.log(params.get('d'));
EDIT bis:
.append() supports to re-use the same key/parameter name, while .set() would have overwritten a previous value.
May be using below code you can pass entire json object in URL Search param
var json = JSON.stringify(myObj);
this.http.get('url'+'?myobj='+encodeURIComponent(json))
There's no API for that. You just need to enumerate over the properties and append them manually, for example using the following function:
function appendParams(params: URLSearchParams, obj: any) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
params.append(key, obj[key])
}
}
}
appendParams(urlSearchParams, { search: 'person' });
Want to share my answer for Angular2 with the option of sending an Array
This is how I use this get function:
this.get('/api/database', {
'age': [1,2,3,4]
})
And the service is something like:
get(url, _params = {}) {
let params = this._processParams(_params);
return this.http.get(url, params).toPromise();
}
_processParams(obj: any) {
/* Convert this
{ age: [1,2,3] }
To:
param.append('age', 1);
param.append('age', 2);
param.append('age', 3);
*/
let params = new URLSearchParams();
for (let key in obj) {
for (let index in obj[key] ) {
params.append(key, obj[key][index]);
}
}
return {
search: params
};
}
Super simple answer/example:
// Create:
const params = new URLSearchParams({
a: 1,
b: 2
})
// OR
// const params = new URLSearchParams("a=1&b=2")
// Append
params.append('c', 'woohoo') // Note: if c param already exists in params, this will replace it (won't be adding new param if already exists, hence no duplications)
console.log(params.toString())
// Prints: 'a=1&b=2&c=woohoo'
Here is my approach. We have a simple requirement where the object is only a key value pair where the value might be a string or an array. We haven't found a use case for nested objects.
So let's say we want to convert this object into a query string or vice versa:
const input = {
ini: 'ini',
itu: 'itu',
ayo: ['desc', 'asc'],
}
Then we have two functions to parse & stringify:
function stringify(input) {
const params = new URLSearchParams();
for (const key in input) {
if (Array.isArray(input[key])) {
input[key].forEach(val => {
params.append(key + '[]', val)
})
} else {
params.append(key, input[key]);
}
}
return '?' + params.toString();
}
function parse(input) {
const payload = {};
const params = new URLSearchParams(input);
for(let [key, val] of params.entries()) {
if (key.endsWith('[]')) {
key = key.replace(/\[\]$/, '');
if (payload[key]) {
payload[key].push(val);
} else {
payload[key] = [val]
}
} else {
payload[key] = val;
}
}
return payload;
}
So the result should be "?ini=ini&itu=itu&ayo%5B%5D=desc&ayo%5B%5D=asc". This is similar to the array format that is found in this example.
Please note that this might not be battle tested, but for us we don't really have complicated object structure.
const url = new URL('/', location.origin);
console.log(url.href); // https://stackoverflow.com/
Object.entries({this:4,that:1}).forEach((item)=>{
// note .set replaces while .append will duplicate params
url.searchParams.append(...item);
});
console.log(url.href); // https://stackoverflow.com/?this=4&that=1

Categories