Im developing a simple app and i need to save a couple of user data so im using AsyncStorage like that:
const storeAge = async (age) => {
try {
console.log("STORED age: " + age);
await AsyncStorage.setItem("#age", age);
} catch (e) {
// saving error
}
};
And im calling this function here:
<SetupInfo
visible={isStartUp}
onRegist={registHandler}
onRegistDataSave={storeAge}
/>
The onRegistDataSave is called on a press of a button on the SetupInfo component:
const addRegistHandlerMemory = () => {
if (!isEnabled) {
props.onRegistDataSave(age / 12);
} else {
props.onRegistDataSave(age);
}
setAge("");
};
...
<Button
title="REGIST"
onPress={() => {
addRegistHandler();
addRegistHandlerMemory();
}}
style={styles.button}
/>
The console.log on store.age is showing the correct input when button is pressed, but when i reload the app and call this:
const getAge = async () => {
try {
const value = await AsyncStorage.getItem("#age");
if (value !== null) {
console.log("valor" + value)
setAppMode(false);
setAge(parseFloat(value));
}
console.log("age " + value);
} catch (e) {
// error reading value
}
};
the value I got is null, why is this happening?
(Well i think i know becouse im doing the same think to save data on one array and the last value is not saved which means that probably is saving on the next render that for me - a noob on this- doent make sense since the set age is an async funtion that should avoid that...)
Oh I figure it out where the error was. Turns out I was saving a number and AsyncStorage just saves Strings, so i just need to add const string = toString(age); on storeAge and save that value.
Related
everyone, I have some problem with fetching data and displaying message on initial loading as well as when I change some of the input filed value. The idea here is to display specific message in two cases after doing some calculation.
const potrosnja = document.getElementById('potrosnja');
const nagib = document.getElementById('nagib');
const input = document.querySelectorAll('input[type="number"]');
const submitBtn = document.getElementById('submitBtn');
const poruka = document.getElementById('poruka');
let str = document.querySelector('input[name="strane-sveta"]:checked').value;
let godisnjaPotrosnja = parseInt(potrosnja.value);
let nagibKrovaInput = nagib.value;
//On button submit it fetches data and calculate the value needed for yearly consumption of energy
//fetching data
async function dataFetch(){
let response = await fetch('./csvjson.json')
let data = await response.json();
data.map(strana => {
strana.strana.map((item, i) => {
try {
if(item == str && nagibKrovaInput == strana.nagib) {
let result = Math.ceil(godisnjaPotrosnja / strana.vrednost[i]);
console.log("try works")
poruka.innerHTML = `You need <span class="kw">${result}</span>`
}
}
catch(err) {
poruka.innerHTML = `Please fill required fields.`
console.log(err)
}
})
})
}
//event listeners
submitBtn.addEventListener('click', () => {
dataFetch()
console.log('clicked')
input.forEach(input => {
if(input.value == ''){
input.classList.add("active");
}
})
})
I can see that the problem is inside try function, it like condition isn't treated on initial load, and I have to reload page so it would work. Can someone help me understanding what is the problem?
Ok, I found solution... First thing I have to do Is to check if nagibKrovaInput == strana.nagib, after I get true, I compared does the indexOf item is equal as str and after I get true, it will display something. I also changed on click on the button to send values to data function as an arguments and It solved the problem. Tnx for help.
I'm working with React, and in my component every time the user types a input the code calls a API.
But this API takes more time to return with few words than with bigger words.
So lets say i type "ne", and takes 7 seconds to return 100+ results, but before that 7 seconds, i wait a second and finish type "new york". That takes miliseconds, than finishes before the previus API call.
Ok, "new york" appears to me on the search, BUT now the first call finishes and overrites the last result.
How can i make that work? Without breaking any of the steps (aka, search in a click of a button stead while tiping), if this is possible
Short example of my code:
class MyComponent extends Component {
state = {
items = []
}
construtor(props) {
this.myCall = _debounce(this.myCall, 400);
}
myCall = async e => {
e.persist();
const query = _get(e, 'target.value', '');
try {
items = await myAPI(query)
this.setState({items})
} catch (error) {
console.error(error)
}
}
...
return (
<>
<input onChange={(e) => myCall(e)} />
{items.map(item => (
<p>item</p>
))}
</>
);
}
You could check that the input value hasn't changed while you awaited the response:
items = await myAPI(query)
if (query === _get(e, 'target.value', '')) {
this.setState({items})
}
Same thing with an implementation that avoids multiple _get calls:
const query = this.query = _get(e, 'target.value', '');
items = await myAPI(query)
if (query === this.query) {
this.setState({items})
}
I am writing the acceptance tests for my application's login feature. At some point, I want to double-check the cookie's expiry time.
Upon clicking on the "Login" button, a graphql query is sent to my server which responds with a Jwt. Upon reception of the jwt, the application sets the cookie with
document.cookie = ...
In my Cypress test, I check the token in the following way:
Then("sa session s'ouvre pour {SessionDurationType}", expectedDuration => {
cy.get('#graphql').then(() => {
cy.wait(1000)
cy.getCookie('token').then(cookie => {
const tokenDuration = getTokenDuration(cookie.value)
expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
})
})
})
With cy.get('#graphql'), I am waiting for the graphql query to return a response. The alias is defined like this:
cy.stub(win, 'fetch', fetch).as('graphql')
Upon reception, the application sets the cookie.
My problem is that I am not fond of the following call:
cy.wait(1000)
Without that call, I always get an undefined cookie.
Is there a way to get that cookie within some time that might be much less than 1000 ms? I tried many things without success...
You must write a recursive promise function, try the following
function checkCookie() {
// cy.getCookie returns a thenebale
return cy.getCookie('token').then(cookie => {
const tokenDuration = getTokenDuration(cookie.value);
// it checks the seconds right now, without unnecessary waitings
if(tokenDuration.asSeconds() !== expectedDuration.asSeconds()) {
// waits for a fixed milliseconds amount
cy.wait(100);
// returns the same function recursively, the next `.then()` will be the checkCookie function itself
return checkCookie();
}
// only when the condition passes returns a resolving promise
return Promise.resolve(tokenDuration.asSeconds());
})
}
Then("sa session s'ouvre pour {SessionDurationType}", expectedDuration => {
cy.get('#graphql').then(() => {
checkCookie()
.then(seconds => {
expect(seconds).to.equal(expectedDuration.asSeconds())
})
})
})
Note that the function must be improved because
I didn't parametrize the expectedDuration etc. (it's out of the scope of showing you how to do that)
it waits forever without a loop counter check
But it works (I checked in another context before replying to you) and if you have some more troubles please share a "working" GitHub repo so I can clone and check it with your own solution.
Let me know if it isn't enough clear 😉
UPDATE
We (me and Tommaso) have written a plugin to help you with this kind of checks, its name is cypress-wait-until.
Please thank the Open Source Saturday community for that, we developed it during one of them Saturdays 😊
I dont like the timeout in this i have to say for dom changes. I have come up with this solution based on #NoriSte Answer together with DomMutation Observers.
getFileUploadItem().get(".upload-item--state i")
.should("have.class", "ngx-fileupload-icon--start")
.then(item => {
const iconEl = item.get(0);
const states: string[] = [];
return new Promise((resolve, reject) => {
const observer = new MutationObserver((mutations: MutationRecord[]) => {
const mutationEl = mutations[0].target as HTMLElement;
const className = mutationEl.getAttribute("class");
states.push(className);
if (className === "ngx-fileupload-icon--uploaded") {
resolve(states);
}
});
observer.observe(iconEl, {
subtree: true,
attributes: true,
attributeFilter: ["class"]
});
});
})
.then((value) => expect(value).to.deep.equal(
["ngx-fileupload-icon--progress", "ngx-fileupload-icon--uploaded"])
);
Based on #NoriSte's answer, I came up with the following working code:
function awaitNonNullToken(elapsedTimeInMs = 0) {
let timeDeltaInMs = 10
if (elapsedTimeInMs > Cypress.env('timeoutInMs')) {
return Promise.reject(new Error('Awaiting token timeout'))
}
return getTokenCookie().then(cookie => {
if (cookie === null) {
cy.wait(timeDeltaInMs)
elapsedTimeInMs += timeDeltaInMs
return awaitNonNullToken(elapsedTimeInMs)
}
return Promise.resolve(cookie.value)
})
}
I transformed that into an ES6 class that I find a bit more elegant:
class TokenHandler {
constructor () {
this.TIME_DELTA_IN_MS = Cypress.env('timeDeltaInMs')
this.TIMEOUT_IN_MS = Cypress.env('timeoutInMs')
this.elapsedTimeInMs = 0
}
getToken () {
if (this.elapsedTimeInMs > this.TIMEOUT_IN_MS) {
return Promise.reject(new Error('Awaiting token timeout'))
}
return getTokenCookie().then(cookie => {
if (cookie === null) {
cy.wait(this.TIME_DELTA_IN_MS)
this.elapsedTimeInMs += this.TIME_DELTA_IN_MS
return this.getToken()
}
return Promise.resolve(cookie.value)
})
}
}
and reworked my step like this:
cy.get('#graphql').then(() => {
const handler = new TokenHandler
handler.getToken().then(token => {
const tokenDuration = getTokenDuration(token)
expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
})
})
This is working perfectly, thanks.
I have following function:
exports.onDataAdded = functions.database.ref('/Lager/Shafts/Rescue/582/582001').onWrite((change, context) => {
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
const original = change.after.val();
return change.after.ref('/Lager/Shafts/Rescue/583/583001').set(original);
});
I am trying to keep the count of product 1 equal to the count of product two (Can't put it in the same ID for several reasons). It executes the function and says the status is ok but does not update the new value of product 2.
What am I missing?
Please try this, Your function is exiting without executing the update.
exports.onDataAdded = functions.database.ref('/Lager/Shafts/Rescue/582/582001').onWrite((change, context) => {
if (change.after.exists()) {
const original = change.after.val();
return admin.database().ref('/Lager/Shafts/Rescue/583/583001').set(original);
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
});
This seems like a noop:
exports.onDataAdded = functions.database.ref('/Lager/Shafts/Rescue/582/582001').onWrite((change, context) => {
if (change.before.exists()) {
return null;
}
Or more precisely: it will only get past this code when you delete /Lager/Shafts/Rescue/582/582001, which is not what you seem to be trying. My guess is that you meant the inverse in your check:
if (!change.before.exists()) {
return null;
}
Is there any way how to catch when is array.push function done? I get data from Firebase database then I push data to array (which is state). Unfortunately as I noticed it changes my state once per every item.
Check screen for better understanding
I have 2 objects in database.
there is code:
componentWillMount(){
const self = this;
const rootRef = firebase.database().ref('/users/' + firebase.auth().currentUser.uid);
const ref = rootRef.child("MyTeams");
let teamsArr = [];
ref.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
self.setState({TeamName: childSnapshot.val()});
teamsArr.push(self.state.TeamName);
self.setState({TeamsToMap: teamsArr});
self.setState({Loaded: true});
console.log('Here: ' + self.state.TeamsToMap);
})
})
.catch((error) =>{
alert(error.message);
})
};
WriteTeams(navigation){
if(this.state.TeamsToMap.length > 0 && this.state.Loaded === true){
console.log('Somewhere: ' + this.state.TeamsToMap.length);
}
}
Since you're looping over the snapshot, the array is modified many times. If you only want to print it after the modification are done: move the console.log() statement after the loop.
ref.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
self.setState({TeamName: childSnapshot.val()});
teamsArr.push(self.state.TeamName);
self.setState({TeamsToMap: teamsArr});
self.setState({Loaded: true});
})
console.log('Here: ' + self.state.TeamsToMap);
})
Since both snapshot.forEach() and teamsArr.push() are synchronous here, the console.log() will run after teamsArr has been fully populated.