I have the code below:
contaTempo(){
setInterval(() => this.setState({tempo: this.state.tempo+1}), 1000)
if (this.state.tempo >= 5) {
this.props.navigation.navigate('Sobre')
}
}
The setInterval works correctly but the if doesn't work. Also, the timer neve stops. Any help?
The if is running right away.
You want to place it inside the function passed to setInterval.
Also, you probably want to remove the timer as well, so call clearInterval() on the value returned by setInterval.
Furthermore, to prevent adding more than necessary to the this.state.tempo, move it to the else of the if statement.
Changed code would be like:
contaTempo(){
let myInterval = setInterval(() => {
if (this.state.tempo >= 5) {
clearInterval(myInterval);
this.props.navigation.navigate('Sobre')
} else {
this.setState({tempo: this.state.tempo+1});
}
}, 1000)
}
Related
I'm setting some state variables in a ReactJS function based on the inputs received onClick. I'm adding these to a running total, and when that total exceeds a given pre-defined level, I want to set a flag. This flag would help me do a few things subsequently, inside the function and outside of it.
The problem I'm facing is that the 'if' is not evaluating correctly, though running totals are calculating fine. I can see them on a rendered element in a div, though on console.log I see the values from the previous time the function was executed onClick.
Because of this, the flag is not getting set correctly, which is causing me much chagrin.
Would deeply appreciate help, since I'm new to the new-age programming (I'm from the dinosaur era of 3rd generation programming).
Copying the relevant piece of code below..
const [assessCourseList, setAssessCourseList] = useState([]);
const [flag1, setFlag1] = useState(false)
const [totqns, setTotqns] = useState(0.0);
const [totmarks, setTotmarks] = useState(0.0);
function createAssessCourse1(e) {
e.preventDefault();
setTotqns(prev => { return (prev + Number(assessCourse.AC_CO_NoOfQns)) })
setTotmarks(prev => { return (prev + Number(assessCourse.AC_CO_TotMarks)) })
if (Number(totqns) >= Number(assessTotQns) || Number(totmarks) >= Number(assessTotMarks)) {
setFlag1(true);
} else {
setFlag1(false);
}
if (!flag1) {
setAssessCourseList(prev => {
return [...prev, assessCourse]
})
}
else {
return
}
}
I'm manipulating some angular services/functions via Chrome console. (I have to specifically do this for a task I'm working on).
What I want to do is wait for the AddBagIfLimitNotReached() function to execute and finish running. And only then access the variable this.option.Quantity.
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].Scope.AddBagIfLimitNotReached = async function(n) {
console.log("tthis", this)
if (this.HasReachedMaximumBaggageAllowance()) {
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].LuggageDrawersService.OpenLuggageLimitReachedDrawer();
return;
}
this.AddBag(n);
console.log("Quantity", this.option.Quantity);
};
With this function, I'm adding a product to my basket. And this.option.Quantity should console.log 1. But it actually consoles.log 0.
However, if I check the object itself, it shows 1.
So I think what is happening, is I'm console.logging my bag quantity, before the bag has actually finished being added to the basket.
For example, if I added a settimeout of 2 seconds, the correct bag value = 1 is console.logged.
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].Scope.AddBagIfLimitNotReached = async function(n) {
console.log("tthis", this)
if (this.HasReachedMaximumBaggageAllowance()) {
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].LuggageDrawersService.OpenLuggageLimitReachedDrawer();
return;
}
this.AddBag(n);
// Returns 1
setTimeout(function(){ console.log("Quantity", this.option.Quantity); }, 2000);
};
Is there a better way I can achieve this, without using settimeout? I have tried async/await/promises, but I still can't seem to find a way to wait for the function to finish loading.
Async/await returns an error - it doesn't like the function this.HasReachedMaximumBaggageAllowance() and throws an error stating this.HasReachedMaximumBaggageAllowance is not a function.
Any tips/ideas would be much appreciated.
I found a solution, I'm using $watch, to watch a key/value, in the this object. And this seems to work:
angular.element(document.querySelector(".quantity-button.plus-button")).controller()._registeredControls[1].Scope.AddBagIfLimitNotReached = function(n) {
let bagCount = this.option.Quantity;
console.log("bagCount", bagCount);
if (this.HasReachedMaximumBaggageAllowance()) {
angular.element(document.querySelector(".quantity-button.plus-button")).controller()._registeredControls[1].LuggageDrawersService.OpenLuggageLimitReachedDrawer();
return;
};
this.AddBag(n);
this.$watch("this.option.Quantity", function (newValue) {
console.log(`Value of foo changed ${newValue}`);
if (newValue > 0) {
document.querySelector(`.luggage-tile-weight-${n.Weight} .tile-title .tick-box`).classList.add("green-tick");
displayGreenTickNoBagSelected();
};
if (newValue === 0) {
document.querySelector(`.luggage-tile-weight-${n.Weight} .tile-title .tick-box`).classList.remove("green-tick");
displayGreenTickNoBagSelected();
};
});
};
I always thought useEffect with empty dependencies will only render once. Here is my code snippet but it renders 2 times:
useEffect(() => {
let entryDataArray = [];
for (let i = 0; i < days; ++i) {
let entryData = [];
let entries = eventEntryList[i];
console.log('entries = ', entries);
for (var j = 0; j < entries.length; ++j) {
console.log('j = ', j);
console.log('entries[j] 1111111 = ', entries[j]);
if (entries[j].runGroup[i] === NOT_ATTENDING) {
continue;
}
console.log('entries[j] 2222222 = ', entries[j]);
let entry = {
lastName: entries[j].userLastName,
firstName: entries[j].userFirstName,
email: entries[j].email,
carNumber: entries[j].carNumber,
paymentMethod: entries[j].paymentMethod,
entryFee: entries[j].entryFee,
paymentStatus: entries[j].paymentStatus ? 'Paid' : 'Unpaid'
};
entryData.push(entry);
}
entryDataArray.push(entryData);
}
setEntryListArray(entryDataArray);
setShowLoading(false);
}, []);
console output shows it renders 2 times. The first time, for loop works as it supposed to - "continue" works under "if (entries[j].runGroup[i] === NOT_ATTENDING)". The 2nd time, "continue" did not get executed.
Am I missing something?
To be clear: useEffect with an empty dependency array runs every time the component mounts. This could be more than once if you have unmounted and remounted your component by accident.
First make sure you're not in StrictMode, as this would be expected in strict mode.
If you aren't in strict mode include a return function in your useEffect which will run on every unmount to detect whether or not your component is unmounting.
useEffect(() => {
// your code
return () => {
// will run on every unmount.
console.log("component is unmounting");
}
}, [])
I thought you run your app in dev mode right?. On Dev mode every time you make the change it hot reload your component every time you make the change to your code.
I have 15 buttons on a page. I need to test each button.
I tried a simple for loop, like
for (var i = 1; i < 15; i++) {
cy.get("[=buttonid=" + i + "]").click()
}
But Cypress didn't like this. How would I write for loops in Cypress?
To force an arbitrary loop, I create an array with the indices I want, and then call cy.wrap
var genArr = Array.from({length:15},(v,k)=>k+1)
cy.wrap(genArr).each((index) => {
cy.get("#button-" + index).click()
})
Lodash is bundled with Cypress and methods are used with Cypress._ prefix.
For this instance, you'll be using the _.times. So your code will look something like this:
Cypress._.times(15, (k) => {
cy.get("[=buttonid=" + k + "]").click()
})
You can achieve something similar to a "for loop" by using recursion.
I just posted a solution here: How to use a while loop in cypress? The control of is NOT entering the loop when running this spec file? The way I am polling the task is correct?
Add this to your custom commands:
Cypress.Commands.add('recursionLoop', {times: 'optional'}, function (fn, times) {
if (typeof times === 'undefined') {
times = 0;
}
cy.then(() => {
const result = fn(++times);
if (result !== false) {
cy.recursionLoop(fn, times);
}
});
});
Then you can use it by creating a function that returns false when you want to stop iterating.
cy.recursionLoop(times => {
cy.wait(1000);
console.log(`Iteration: ${times}`);
console.log('Here goes your code.');
return times < 5;
});
While cy.wrap().each() will work (one of the answers given for this question), I wanted to give an alternate way that worked for me. cy.wrap().each() will work, but regular while/for loops will not work with cypress because of the async nature of cypress. Cypress doesn't wait for everything to complete in the loop before starting the loop again. You can however do recursive functions instead and that waits for everything to complete before it hits the method/function again.
Here is a simple example to explain this. You could check to see if a button is visible, if it is visible you click it, then check again to see if it is still visible, and if it is visible you click it again, but if it isn't visible it won't click it. This will repeat, the button will continue to be clicked until the button is no longer visible. Basically the method/function is called over and over until the conditional is no longer met, which accomplishes the same thing as a for/while loop, but actually works with cypress.
clickVisibleButton = () => {
cy.get( 'body' ).then( $mainContainer => {
const isVisible = $mainContainer.find( '#idOfElement' ).is( ':visible' );
if ( isVisible ) {
cy.get( '#idOfElement' ).click();
this.clickVisibleButton();
}
} );
}
Then obviously call the this.clickVisibleButton() in your test. I'm using typescript and this method is setup in a class, but you could do this as a regular function as well.
// waits 2 seconds for each attempt
refreshQuote(attempts) {
let arry = []
for (let i = 0; i < attempts; i++) { arry.push(i) }
cy.wrap(arry).each(() => {
cy.get('.quote-wrapper').then(function($quoteBlock) {
if($quoteBlock.text().includes('Here is your quote')) {
}
else {
cy.get('#refreshQuoteButton').click()
cy.wait(2000)
}
})
})
}
Try template literals using backticks:
for(let i = 0; i < 3; i++){
cy.get(`ul li:nth-child(`${i}`)).click();
}
This was asked upon searching here, but the solutions were not working, or I have missed something.
This is the snippet of the code
tick(rev_new_arr) {
if(rev_new_arr.length > 0){
this.setState({
sim_play_date : rev_new_arr[0]
},()=>{
rev_new_arr.shift()
})
}else{
this.stopPlay()
}
}
playMap(){
const startDate = this.state.simulation_date;
const sim_dates = this.state.sim_dates;
const index_simdate = parseInt(sim_dates.indexOf(startDate) + 1, 0);
const new_arr = sim_dates.slice(0,index_simdate);
const rev_new_arr = new_arr.reverse();
this.timerID = setInterval(()=> this.tick(rev_new_arr), 1000);
}
stopPlay(){
console.log(this.timerID);
clearInterval(this.timerID);
}
setInterval works but when adding the function stopPlay() on click event in a button, it does not stop and still calls the tick function.
EDIT: I tried logging the timerID in console..It outputs 2 ids. I think that is the reason, why it's not stopping even calling clearInterval. What must be the reason of this?
Are your methods playMap() stopPlay() and tick() bound to the class? If not, try defining them like:
stopPlay = () => {
...
}
clearInterval is referring to global context,so bind it.
stopPlay(){
console.log(this.timerID);
clearInterval(this.timerID).bind(this);
}