chrome.storage not working as expected - javascript

I am trying to save a list of dictionary objects in the chrome storage. But the following code seems to not work as expected.
When the extension loads for the first time and there is no goal object in the storage, runtime.lasterror object should be set and the code in that part should get executed. But it isn't.
When I uncomment the chrome.storage.sync.set line and save the object and the next time I call the function expecting it to save a list, it doesn't. It does not give any of the alert boxes.
function isPgUrl(pg_url,gl_name) {
if(pg_url && gl_name) {
dic_url={
"name":gl_name,
"pg_url":pg_url
}
//chrome.storage.sync.set({"goal":[dic_url]});
chrome.storage.sync.get(["goal"], function(data) {
if(chrome.runtime.lastError) {
chrome.storage.sync.set({"goal":[dic_url]},function() {
alert("blah");
});
alert("here");
return;
}
var list=data.goal;
list.append(dic_url);
alert(list);
chrome.storage.sync.set({"goal":list},function() {
alert("lalala");
return;
});
});
}
}

You'll never get chrome.runtime.lastError set for missing data. It's not an exception - you just get undefined value. So your check should be:
if(!data.goal) { ... }
or
if(typeof data.goal === "undefined") { ... }
If you uncomment that line, you need to be aware that chrome.storage is asynchronous: the data is not in storage until the callback of .set(). So your .get() that is executed immediately after calling .set() may get a snapshot of the older view of the storage - making your code fail at list.append(dic_url);
Not that Array.prototype.append exists in the first place. You should be using .push().
Chrome Storage has a more efficient way of setting a default-if-not-in-storage value, by using an Object as a query:
chrome.storage.sync.get({key: "defaultValue"}, function(data) {
// data.key will be the stored value, or "defaultValue" if not in storage
});
So, if I understand the purpose of your code correctly (append dic_url to goal in storage), this will do it:
// Makes more sense to default to empty list
chrome.storage.sync.get({goal: []}, function(data) {
var list = data.goal;
list.push(dic_url);
chrome.storage.sync.set({goal: list}, function() {
// Stoarge updated, dic_url appended to goal
});
// Storage is not yet updated - set() is async
});
// Storage is not yet updated - get()/set() are async

Related

Seeking proper way to use the get() method of INDEXEDDB data store

I am attempting to use a simple indexeddb 'get' method to retrieve a keyed record from an existing data store. For some reason that i have been unable to find, though the result of my 'get' request is 'successful', the returned value is 'undefined'.
The code below is called from an event listener that is fired when the user clicks on a button in a row of a table, indicating the user wants details on that particular row. Each row in the table represents a record in the indexeddb data store that has already been created. There are 8 values of interest in each row, but only 3 are displayed in my html table. I am simply attempting to access the row in the data store to get all 8 values in order to pass them along to the next process.
The following code is called from an event listener created on a 'Select' button for each row...
async function getGameInProgressDetails(gameID) {
try {
db = await idbConnect(DBName,DBVersion);
let tx = db.transaction(['gamesList'], 'readonly');
let gameStore = tx.objectStore('gamesList');
// I have confirmed the 'gameID' passed in is the key value that i would expect
// to retrieve the desired result.
let req = gameStore.get(gameID); // gameID comes from the selected row in the html table.
req.onsuccess = (ev) => {
console.log('Success');
let request = ev.target;
console.log(request); // returns an IDBRequest object with result: undefined and error: null.
let theGame = request.result;
console.log(theGame ); // displays 'undefined'.
}
req.onerror = (err) => {
console.warn(err);
};
} catch (e) {
console.warn(e);
}
I get the 'success' message indicating that the 'get' operation was successful, but my result is 'undefined'. Could someone please tell me if i am missing a step or if there's another way to go about this that i should look into? I've looked at a variety of tutorials and i must be overlooking something 'obvious'.
I discovered the problem with my code/approach and am answering my own question. The reason that the above code was not working was not because of my indexeddb code or logic at all.
What i discovered was that the index value that i had passed into the routine needed to be cast as an integer before the get() method call, JS was treating it as a string value. I was confused by the fact that i had checked the value in a console.log statement and it had shown the appropriate value. What i hadn't considered was how JS evaluated what type the variable value was.
For those coming later and seeing this, my final code was thus:
async function getGameInProgressDetails(gameID) {
db = await idbConnect(DBName,DBVersion);
let tx = db.transaction(['gamesList'], 'readonly');
var gameStore = tx.objectStore('gamesList');
let gameIndex = gameStore.index("gameIDIdx");
let request = gameIndex.get(parseInt(gameID)); //!! NOTE THE parseInt!!
request.onsuccess = function() {
if (request.result !== undefined) {
console.log("Games", request.result);
} else {
console.log("No such games.");
}
}

Multiple receive and awaiting for request with similar ID received from before executing the function inside Javascript

Could you please help me with solving the following problem I would like to get values from the array returned by the socket which have similar ID's and pass them to a function.
First Received Request
{
"ID":"4567132",
"GroupType":"2"
"Name":"John Chris"
"SocialID":"68799"
"SecurityID":"18799-er7ree-781347a-71237n"
}
Second Received Request
{
"ID":"4567438",
"GroupType":"2"
"SocialID":"68799"
"SecurityID":"68789-4d37er-98c5347-e05d9b"
}
I would like to get the following Expected Results combined from the First and Second. But taking into consideration other request also coming in from the api.
{
"GroupType":"2"
"SocialID":"68799"
"PublicSecurityID":"18799-er7ree-781347a-71237n"
"PrivateSecurityID":"68789-4d37er-98c5347-e05d9b"
}
What make things complicated is that both first and second are received at the same time and maybe there can be other request the would be received by the socket. How can I group only those incoming messages that have a similar SocialID. Also how can I await for all the similar request from the socket and only execute once there are no more request.
Here is the code for receiving the socket
ReceiveSocket.on("socketMessage", (returnedData) => {
// code here
});
I'm not sure how to approach the problem logically could you explain and give the solution to handling the problem. Thanks!
What about something like this:
ReceiveSocket.on('socketMessage', returnedData => {
// objectsBySocialID always starts empty to make sure that
// sendRequest() only receieves new data. Notice that all previous
// data was already handled when it arrived, just like the
// current batch of data is being handled now.
const objectsBySocialID = {};
returnedData.forEach(obj => {
// If there's already one or more objects with the SocialID of the
// current object, then just add it to the array that contains the
// objects that have that SocialID.
if (objectsBySocialID[obj.SocialID]) {
objectsBySocialID[obj.SocialID].push(obj)
}
// Otherwise, initialize the array that will contain objects with
// this object's specific SocialID and assign it to the
// corresponding key.
else {
objectsBySocialID[obj.SocialID] = [obj]
}
// objectsBySocialID only contains the latest changes.
sendRequest(objectsBySocialID);
});
});
Using the data from your example, objectsBySocialID should look like this:
{
'68799': [
{
'ID':'4567132',
'GroupType':'2',
'Name':'John Chris',
'SocialID':'68799',
'SecurityID':'18799-er7ree-781347a-71237n',
},
{
'ID':'4567438',
'GroupType':'2' ,
'SocialID':'68799',
'SecurityID':'68789-4d37er-98c5347-e05d9b',
},
{
'GroupType':'2',
'SocialID':'68799',
'PublicSecurityID':'18799-er7ree-781347a-71237n',
'PrivateSecurityID':'68789-4d37er-98c5347-e05d9b',
},
],
}
and when you're done collecting and grouping data, you should be able to pass objectsBySocialID as an argument to the function that deals with the ordered data (sendRequest() in this example).

How do I wait for the value of a firebase realtime database reading?

I am stuck trying to do the following: when a button is clicked I need to check a value from my realtime database (I have to wait for the response), if the value exists I have to do some stuff (publish new data), but if the value doesn't exist then do nothing.
The code that I have so far:
let ref3 = firebase.database().ref("dispositivos")
ref3.once('value').then(function (snapshot) {
if (snapshot.hasChild("value")) {
console.log("exists");
ref.update({ //Link mac to user
[p]: cant,
[cant]: mac
}).then(function(){
console.log("Link done!");
});
}
}
else {
// if the child doesn't exist, do other code
}
});
I tried to use then as I read in some posts and await but they don't seem to work. Sometimes the code works, but sometimes not (this occurs both when "value" exists and when it does not).

Querying for local storage entry without throwing errors

Working on a chrome extension. I am using the following to save some data to my local storage:
chrome.storage.local.set({ [variablyNamedEntry]: someObjectToBeSaved });
Elsewhere in my code I want to query if the entry exists and if it does, I will want to local some variable "myVar" with the object.
If the entry exists, this code works to achieve my goals:
chrome.storage.local.get(null, function(result){
myVar = result[variablyNamedEntry];
}
But if no entry exists for "variablyNamedEntry" it throws an error. I could manage this error with a try/catch sequence. But that can't be the best approach, given that I know that it will not find the entry a very large percentage of the time.
How can I achieve my goal?
Update:
I tried using:
chrome.storage.local.get([variablyNamedEntry], function(result){
if (result != undefined)
myVar = result[variablyNamedEntry];
}
But I still get the following error if the entry does not exist:
extensions::uncaught_exception_handler:8 Error in response to storage.get: TypeError: Cannot read property 'someProperty' of undefined
Please be aware the items parameter for the callback of chrome.storage.local.get is always an object and would never be undefined.
Assuming you have a key-value in which key is 'Sample-Key', you could use the following code
chrome.storage.local.get(null, function(result){
if(typeof result['Sample-Key'] !== 'undefined') {
console.log(result['Sample-Key']);
}
});
Or
chrome.storage.local.get('Sample-Key', function(result){
if(typeof result['Sample-Key'] !== 'undefined') {
console.log(result['Sample-Key']);
}
});

Firebase field delayed update

I have a Firebase with a users reference, which has a field user_id.
([Firebase]/[app]/users/user_id)
I insert a user & assign a user_id. However, when I read the value of user_id from userRef (a reference to users), it does not read it the first time. Subsequent reads work perfectly fine.
Using the debugger, I can see that when the user is created, a user_id is assigned. It seems like my first call refreshes the Firebase reference, so that subsequent calls are now seeing the udpated Firebase (I don't think that is what it is - that is just how it appears).
This is my code to read the value of user_id:
var userID = 0;
userRef.on('value', function(snapshot) {
userID = snapshot.val().user_id;
});
alert(userID);
The first time, the alert shows 0. Every time after that, it shows the correct value.
To make the problem even stranger, I also have a games reference with a game_id, created in the same way as user. But my read on game_id (in the exact same way & at the same time) works every time.
Any ideas?
The issue here is that .on() doesn't (in general) trigger your callback function immediately. In particular, the first time you do a .on() at a location, Firebase has to go ask the server for the current value, wait for the response, and THEN call your callback. And it does this all asynchronously.
The way your code is currently written, "alert(userID);" is being run before your callback code ("userID = snapshot.val().user_id;") so it always reports 0 the first time. The simple fix is to move the alert() inside your callback:
var userID = 0;
userRef.on('value', function(snapshot) {
userID = snapshot.val().user_id;
alert(userID);
});
Here's a common methodology to wait on two callbacks, using using jQuery's Promise model and once:
var userID = 0;
// sends a callback to fx where the results can be stored
function defer( fx ) {
return function() {
var deferred = $.Deferred();
fx( function(snapshot) { deferred.resolve(snapshot.val(); } );
return deferred.promise();
}
}
$.when( // wait for both actions to complete
defer( function(callback) { userRef.once('value', callback) }),
defer( function(callback) { widgetRef.once('value', callback) })
).then( function(values) {
// both deferreds are done now
// and values contains an array with the snapshot.val() from each call
console.log(values);
});

Categories

Resources