Switching Values with chrome storage - javascript

I want to save a boolean value by clicking on a picture that changes its state from true to false every time I click onto the picture.
So simply I want to write something like
function SwitchByImage(propertyName) {
var oldValue=chrome.storage.sync.get({propertyName}, null);
var newValue=!oldValue;
chrome.storage.sync.set({propertyName:newValue},null);
if (newValue) {
$("#whateverimage").attr("src","upimage.jpg");
} else {
$("#whateverimage").attr("src","downimage.jpg");
}
}
I know that this does not work. Where I added "null" should be a function. My problem is: The storage works asynchronous, so it does not seem to be possible to write and read my data in a sequence.
What is the best way to get around this issue?

Since chrome.storage.sync.get is asynchronous, the fetched value will be available in the callback, so that is where the rest of the code should be placed:
function SwitchByImage(propertyName) {
chrome.storage.sync.get(propertyName, function(items) {
var oldValue = items[propertyName];
var newValue = !oldValue;
chrome.storage.sync.set({ propertyName: newValue });
if (newValue) {
$("#whateverimage").attr("src", "upimage.jpg");
} else {
$("#whateverimage").attr("src","downimage.jpg");
}
});
}

Related

Can you alter a statement in a javascript function after is run once

I'm having a hard time figuring this out. I'd like the xxp.run.pause(); to be replaced by xxp.run.play(); after the initial code below is actioned by a user once. I've tried creating a closure but I'm not sure I set it up right. Any help would be very much appreciated.
doSkip: function() {
XXP.run.removeListener('canper', XXP.Skip);
XXP.run.currentTime = XXP.skipTo;
XXP.run.pause(); // this is what I would like to change
}
You may set a flag somewhere which records whether or not the doSkip function has been called before:
var hasSkip = false;
doSkip: function() {
XXP.run.removeListener('canper', XXP.Skip);
XXP.run.currentTime = XXP.skipTo;
if (!hasSkip) {
XXP.run.pause();
hasSkip = true;
}
else {
XXP.run.play();
}
}
You can wrap the function in an IIFE with a persistent variable that checks to see if it's been paused. This has the advantage over having a separate variable elsewhere because hasPausedOnce is only needed for the doSkip function - no need to populate the outer scope (which can have readers of your code worrying about whether hasPausedOnce is going to be altered elsewhere)
doSkip: (() => {
let hasPausedOnce = false;
return function() {
XXP.run.removeListener('canper', XXP.Skip);
XXP.run.currentTime = XXP.skipTo;
if (!hasPausedOnce) {
XXP.run.pause();
hasPausedOnce = true;
} else XXP.run.play();
};
})()

Reactjs: Checkbox state is update, then reverted when callback function terminates

I'm pretty new to react and I ran into a weird issue today. I have a function called handleCheckBoxClick()
handleCheckboxClick : function (e) {
this.setState({isChecked : e.target.checked},
function () {
if (this.state.isChecked) {
this.props.addToTransactionSubmissions(
this.props.submissionGuid,
this.props.paymentInfo
);
} else {
this.props.removeFromTransactionSubmissions(
this.props.submissionGuid
);
}
}
);
}
This particular function calls a function passed down through a parent called addTo/removeFromTransactionSubmission. The code for both is as follows:
addToTransactionSubmissions : function (guid, paymentInfo) {
if (Object.keys(this.state.transactionSubmissions).length === 0) {
this.setState({submissionType : paymentInfo.status_description.toLowerCase()},
function () {
console.log('it set the state though');
console.log(this.state.transactionSubmissions);
this.toggleButtons(this.state.submissionType);
}
);
}
var newTansactionSubmissions = update(this.state.transactionSubmissions,
{
$merge : {[guid] : paymentInfo}
});
this.setState({transactionSubmissions : newTansactionSubmissions},
function () {
console.log('state is now', this.state.transactionSubmissions);
}
);
},
removeFromTransactionSubmissions : function (guid) {
if (Object.keys(this.state.transactionSubmissions).length === 0) {
this.setState({submissionType : undefined},
function () {
this.toggleButtons(this.state.submissionType);
}
);
}
var newTransactionSubmission = update(this.state.transactionSubmissions,
{
[guid] : {$apply: function (x) {return undefined}}
});
this.setState({transactionSubmissions : newTransactionSubmission},
function () {
console.log('here in remove Transaction');
});
}
The problem I run into is that when addTo/removeFromTransactionSubmissions is called, the checkbox does not changes states, even though the state is changed before addTo/removeFromTransactionSubmissions is called. Through further debugging using Firebug, I discovered that 1) the functions are all being called properly, 2) if I do not set state in addTo/removeFromTransactionSubmissions everything runs without a hitch, and 3) the checkbox becomes unchecked after handleCheckboxClick completely finishes.
I suspect that for whatever reason, the state is being lost when Reactjs is trying to update the DOM. However, I do not know why this is the case and don't know how to further debug. And for clarification, the checkbox is in the child component whereas the transactionSubmissions state is in a parent, and on the click of a checkbox, transactionSubmissions is modified (Child Action modifies Parent state). If this is the wrong way to go about the problem, please tell me.
Basically what I want to do is every time I click/unclick a box, it removes the corresponding object to/from a map of ids to the object. Am I doing something incorrectly?
Thanks for the help!
I think you should use another aproach.
handleCheckboxClick : function (e) {
this.setState({isChecked : e.target.checked})
}
Add a method componentWillUpdate(https://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate) or componentDidUpdate(https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate) and handle there the changes that must occur after state change
componentWillUpdate()
{
if (this.state.isChecked)
{
this.props.addToTransactionSubmissions(
this.props.submissionGuid,
this.props.paymentInfo);
} else {
this.props.removeFromTransactionSubmissions(this.props.submissionGuid);
}
}
Also you should not call setState sequencially, it can throw some errors by trying to mutate a component while it was updating.
Every time your code calls setState, react goes trought all the dom, check what has changed and render the changes again, saving processing. Ref:https://facebook.github.io/react/docs/component-api.html#setstate

sportsBasketballChange another place its not setting state properly

I tried to say is I am not able to set the value using setState in sportsBasketballChange function but I am able to set it in sportsSoccerChange function
i am new to react.js
i am trying to set the value using setState.
in sportsSoccerChange function its correctly setting setState.
but sportsBasketballChange another place its not setting state properly.
can you guys tell me how to fix it.
providing my code below.
part of code
sportsSoccerChange(value) {
this.props.onChange();
let processedValue = value;
// sportsMessages sportsAirFalling
processedValue = sportsAirFallBALL(processedValue, this.props.sportsAirFall);
// sportsSuceessOnTime-ation
let sportsSuceessOnTime-ationResult = sportsSuceessOnTime-ateBALL(processedValue, this.props.sportsDrive);
if (sportsSuceessOnTime-ationResult === true) {
this.setState({ sportsOutcome: 'sportsSuceessOnTime-' });
///here i get value as sportsSuceessOnTime-
}
//this.setState({ isBALLValid: sportsSuceessOnTime-ationResult });
// formatting
processedValue = formatBALL(processedValue, this.props.sportsLongJump);
// set value in local component state
this.setState({ sportsMessagesValue: processedValue });
},
sportsBasketballChange() {
if (this.state.sportsOutcome === 'female') {
this.setState({ sportsOutcome: 'sportsSuceessOnTime-' });
///here i don't get value as sportsSuceessOnTime-
}
},
whole code here
https://gist.github.com/js08/e20c02bf21242201c1525577d55dedbc
I'm assuming that you are checking the value of this.state at those commented lines, either using logging or debugging.
setState is asynchronous. This means that there is no guarantee that the changes have occurred by the time you reach the next line of code. However, setState allows you to provide a callback function to be run after the state has finished updating. That is where you should be checking the updated value.
sportsBasketballChange() {
if (this.state.sportsOutcome === 'female') {
this.setState({ sportsOutcome: 'sportsSuceessOnTime-' },
function(){
console.log(this.state.sportsOutcome); // == 'sportsSuceessOnTime-'
}
);
console.log(this.state.sportsOutcome); // untrustworthy
}
},

chrome.storage.sync.get sync with outer level object, but inner object is not sync?

I am trying to use chrome.storage.sync.get to get back the settings. What I don't understand is that when I call console.log(settings), it returns the correct values. But if I call console.log(settings.speeds), it returns the old values. I think this has something to do with the async nature of chrome.storage.sync.get. Can someone please explain what's going on here? And if there's a solution to this. I tried using callback but it didn't help. I guess one solution is to use just one level but that's not what I want.
Thanks all for the help.
var settings = {
speeds: {
speedInput1: 1.0, // after get, new value should be 11.23
speedInput2: 2.0 // after get, new value should be 4.50
},
shortcuts: {
shortCut1: '1',
shortCut2: '2'
}
};
chrome.storage.sync.get(settings, function(result) {
// Retrieve speed settings
for (var key in settings.speeds) {
if (key in result.speeds) {
settings.speeds[key] = result.speeds[key];
}
};
// Retrieve shortcut settings
for (var key in settings.shortcuts) {
if (key in result.shortcuts) {
settings.shortcuts[key] = result.shortcuts[key]
}
};
});
console.log(settings); // correct updated values
console.log(settings.speeds); // old values
I found a workaround for anyone who's interested. I wrapped the get call with a function and call that function and that solve the issue. As to why this solves the issue...I have no idea. Below is an example.
function getChromeStorage() {
chrome.storage.sync.get(settings, function(storage) {
// get stored values back;
}
getChromeStorage(); // calling it as a function solves the asynchronous issue

Proper javascript functions structure

I'm getting data from my firebase
//user balance check
var balanceRef = new Firebase('https://****.firebaseIO.com/arcade/grabbit/'+category+'/'+brand+'/'+gameId+'/'+'activePlayers'+'/'+userId+'/');
Here's the function that gets the data
//check user balance
function checkBalance(){
balanceRef.on('value', function(snapshot) {
if(snapshot.val()=== null){
mLeft=0
} else{
mLeft=snapshot.val().tokensLeft
}
return mLeft
})
}
When the user clicks a button I 1st check their balance
$('#grabbit').click(function() {
//call checkBalance function on click
var myTokensLeft=checkBalance();
});
the problem here is it's returning the function value as NaN or undefined
I've tested repeated, the function does return a value. Why can't It pick up the value on click? Am I doing something wrong with the structure. I'm very new to javascript
balanceRef.on looks like an async function to me, which is why you won't get a return value.
try something like this:
//check user balance
function checkBalance(callback){
balanceRef.on('value', function(snapshot) {
if(snapshot.val()=== null){
mLeft=0
} else{
mLeft=snapshot.val().tokensLeft
}
callback(mLeft);
})
}
$('#grabbit').click(function() {
//call checkBalance function on click
checkBalance(function(myTokensLeft){
// do something with myTokensLeft
});
});
EDIT: more details
the function balanceRef.on does not return your desired data, it only attaches the function function(snapshot)... to the object balanceRef's value event.
When the object balanceRef's value event gets triggered (i.e. data is available), your function function(snapshot)... gets executed, but it's return values goes nowhere, because the javascript parser has already moved on.
try this:
function checkBalance(){
balanceRef.on('value', function(snapshot){
return 'foo';
});
return 'bar';
}
$('#grabbit').click(function(){
console.log(checkBalance());
// this will print 'bar' in your
// in your console, not 'foo'
});
EDIT 2: to avoid callback chaining, one can use a variable that will be common to both functions. (not a very good practice though, since you cannot be sure that the value has been set, when you want it!)
(function(){
// added the closure to avoid myTokensLeft cluttering
// into global variables
var myTokensLeft;
balanceRef.on('value', function(snapshot){
var mLeft;
if (snapshot.val()=== null){
mLeft=0
} else{
mLeft=snapshot.val().tokensLeft
}
myTokensLeft = mLeft;
});
$('#grabbit').click(function(){
// do something with myTokensLeft
});
}());
It seems to me that on your click event you only create another listener to "value" event and gods know how and when that event is triggered and where the function returns your mLeft.
What is happening in your code is that after each click on "#grabit" always new listener is created, but the function inside is not necessarily to be called and if it is called it is called asynchronously which means by the time it is finished you already got "undefined".

Categories

Resources