I have an IONIC 4 application where I need to call an api every 20 seconds and if the user moves to other page need to stop calling that api. I am able to make the api call at every 20 seconds but not able to stop it when I move to some other page. Here is my code below, may I know where I went wrong?
rateTimer:any;
constructor(private loginServiceService: LoginServiceService) {
this.loginServiceService.getappData();
this.rateTimer=setInterval(() => {
this.loginServiceService.getappData();
}, 10000);
}
// When I move to other page, I clear the setInterval from here
ngOnDestroy() {
clearInterval(this.rateTimer);
}
As far as I know Ionic has a cache for page-navigation which is why ngOnDestroy/ngOnInit will not always work. However, there's ionViewDidLeave which should definitely fire, once the current page is moved away from (see https://ionicframework.com/docs/api/router-outlet#life-cycle-hooks for more details):
export class YourComponent {
ionViewDidLeave() {
// Do actions here
}
}
Related
I am trying to build a dinosaur running game in React much like google chrome's.
My idea is that I will run a function at the exact moment the object is suppose to hit the dinosaur, around 3 seconds
function check4Death() {
if (playerClass !== '') {
console.log('safe')
}
else {
console.log('nope')
clearInterval()
}
}
setInterval(check4Death, 3000)
This function checks to see if the player is currently in the air
As my method of jumping is adding and then removing a class from my playerClass object
function Jump() {
setPlayerClass('jump')
setTimeout(() => {
setPlayerClass('')
}, 500);
}
Instead of the function telling me either safe or nope every three seconds, I get this
I am very confused as to why this is happening, I have a link to my full code here
On my Angular web-app, when a browser refreshes or reloads, the login for the user is lost and he must go through the login steps again. I would like to allow the login status remain open for the user after the browser reload, but only within a short interval, perhaps 10 seconds or so. When the web-app reloads, it checks if the come-back is within these 10 seconds interval. For that I need to know when the refresh/reload or the last moment the app was active.
How do we determine the moment/time right before the browser reloads (or closes) or the nearest time to that?
You can capture the reload event and store a timestamp to the localstorage, then do check and comparison each time your app is initiated. A simple function can be:
window.onbeforeunload = ()=>{
localStorage.setItem('last_reload_time',(new Date()).getTime());
}
Then in your app, check for last_reload_time and do compare with current timestamp.
Another DOM event that may help is visibilitychange
In its simple JS form, I used the answer by Metabolic as the starting point.
However, the functionality of the event: "onbeforeunload" is a bit tricky as stated here: MDN, and few browsers, e.g. Chrome ware giving me cold shoulder on the event - not firing. Note, that in most cases the reload event fires, but is not caught by the debugger and if you'll place breakpoints in (eg: in fn: onBeforeUnload() ), do not expect them to stop your code on the event!
I used this approach with rxjs to resolve - on Angular.
import { fromEvent } from 'rxjs';
persistKey: string = 'TIME_BEFORE_UNLOAD';
//// eventually, instead of rxjs: fromEvent(...)
//// you can use this:
// #HostListener("window:beforeunload", ["$event"])
// unloadHandler(event: Event) {
// this.onBeforeUnload(event);
// }
ngOnInit() {
// use this to test and see;
// the time stamps should change in console
// after each reload click
console.log('-- Stored time before unload: ',
localStorage.getItem(this.persistKey));
this.subscribeToBrowserEvents();
}
private subscribeToBrowserEvents() {
fromEvent(window, 'beforeunload')
.subscribe(event => this.onBeforeUnload(event));
}
private onBeforeUnload(event) {
const val: string = new Date().toISOString();
localStorage.setItem(this.persistKey, val);
}
I'm building an app that has a timer to request geolocation while the timer is active. For a timer I'm using react-native-background-timer. Which is kind of working, but not exactly as I want.
With this piece of code:
BackgroundTimer.runBackgroundTimer(() => {
console.log('tic');
},
1000);
the timer is stopping when the app is in the background. While with this piece of code:
const intervalId = BackgroundTimer.setInterval(() => {
console.log('tic');
}, 1000);
it runs constantly even in the background, but I'm not able to stop it. When I run BackgroundTimer.clearInterval(intervalId);, the timer still runs. Even when I leave the screen and go back to my Home screen, the timer still ticks and never stops. This is not ideal, because I need timer to run for a few minutes and then stop.
I set the timer to 1 second to update time left on the screen. I was thinking about setting a timer once for 6 minutes, but then how do I update the state every second? Making 2 timers for this feels like a bad practise, even though it would work.
So to make it more clear, the user suppose to engage in certain activity like walking for a few minutes. So I can't let the timer to stop when user is answering a call or opened a music app to switch music or something else. Timer still needs to run and I need to measure the number of steps and distance with geolocation. It need to work flawlessly even if user opened another app, forgot about my app, and it would still run for the remaining time, then made a record to the database and stopped.
Try the following code snippet,
works both on android and ios
import { DeviceEventEmitter, NativeAppEventEmitter, Platform } from 'react-native';
import _BackgroundTimer from 'react-native-background-timer';
const EventEmitter = Platform.select({
ios: () => NativeAppEventEmitter,
android: () => DeviceEventEmitter,
})();
class BackgroundTimer {
static setInterval(callback, delay) {
_BackgroundTimer.start();
this.backgroundListener = EventEmitter.addListener("backgroundTimer", () => {
this.backgroundTimer = _BackgroundTimer.setInterval(callback, delay);
});
return this.backgroundListener;
}
static clearInterval(timer) {
if (timer) timer.remove();
if (this.backgroundTimer)
_BackgroundTimer.clearInterval(this.backgroundTimer);
_BackgroundTimer.stop();
}
}
export default BackgroundTimer;
Usage
const timer = BackgroundTimer.setInterval(callback, 1000);
BackgroundTimer.clearInterval(timer)
For some reason I got the following error when using #Aravind Vemula's answer.
When calling BackgroundTimer.clearInterval(timer); the following error appears:
timer.remove is not a function
That's why I modified the code slightly.
// parameter removed
static clearInterval() {
// ADD this if statement
if (this.backgroundListener){
this.backgroundListener.remove();
}
if (this.backgroundTimer)
_BackgroundTimer.clearInterval(this.backgroundTimer);
_BackgroundTimer.stop();
}
The above code checks if a backgroundlistener is registered. If yes it removes all listeners and especially our backgroundTimer.
Usage:
BackgroundTimer.clearInterval(); // removed parameter
After my change, everything is working fine on iOS 14.3.
#Aravind Vemula's answer working properly. But if user open the app from the background and timer code is added in background handler then when you stop the timer it is not working. So following changes you need to make in both the methods.
static setInterval(callback, delay) {
if (!this.backgroundListener && !this.locationTimer) {
_BackgroundTimer.start();
this.backgroundListener = EventEmitter.addListener('backgroundTimer', () => {
this.locationTimer = _BackgroundTimer.setInterval(callback, delay);
});
return this.locationTimer;
}
}
static clearInterval() {
if (this.backgroundListener) {
this.backgroundListener.remove();
}
if (this.locationTimer) {
_BackgroundTimer.clearInterval(this.locationTimer);
}
this.backgroundListener = false;
this.locationTimer = false;
_BackgroundTimer.stop();
_BackgroundTimer.start();
}
I have a program written in vue and electron.
This program calls an init function that takes around 15 seconds to complete.
The issue I am having is that I can't seem to make this run in a background thread or after the component has rendered a loading view. The application is just a white blank screen while the init function is running.
I would assume that it would be easiest to just load a loading view and let it be frozen during startup, so how would I actually go about doing that?
I tested with something like this:
updated() {
console.log("running init");
init();
this.loading = false;
console.log("completed init");
}
but it appears as if it isn't always called.
To force it I updated some data in the mounted hook, but then it freezes on the white screen
I have a toggle button in a react component:
toggleSpeak = () => {
this.setState({buttonOn: !this.state.buttonOn});
}
And the button changes its style depending on its state:
<img key="headphones" className={audioclass} src={this.state.buttonOn ? white : black} onClick={this.toggleSpeak}/>
This also triggers some stuff in a child component:
play={this.state.buttonOn}
This triggers some speechSynthesis playback, which sometimes takes a while. The problem is that I want the user to realize that something is happening right away. The button, however, doesn't change its style right away. As long as I'm triggering something else, whether it is through a passthrough property to the child as above, or through triggering a redux action, it still delays changing color for a few seconds.
I want to change color right away without delay, so the user knows not to keep repushing it. How can I accomplish this?
this.setState({}) function is indeed asynchronous so what you are claiming is likely to be true for a very short number of milliseconds considering that all you have in the trigger is
toggleSpeak = () => {
this.setState({buttonOn: !this.state.buttonOn});
}
The noticeable delay you speak of should be unnoticeable. I would think that the delay is being imposed from elsewhere. (say you require some other synchronous code to run before this.setState({}). Do show us more of the relevant code so that we can get better grasp of what's happening.
Are you doing the speechSynthesis in render?
You should call the function that does the speechSynthesis after toggling the button.
As far as UX is concerned, I would recommend that you show a loading indicator while you are doing a task that might take some time to finish. Also, you could disable the button until the speechSynthesis is finished.
toggleSpeak = () => {
if(!this.state.doingSpeechSynthesis) {
this.setState(
{buttonOn: !this.state.buttonOn, doingSpeechSynthesis: true},
() => speechSynthesis(args, this.setState{doingSpeechSynthesis: false}));
}
}
I'm not sure if this is the "react" way of doing things, but I came up with a solution that works. I split up the property I pass to turn on the player from the button toggle.
state = {
buttonOn: false,
play: false
}
Button attributes are the same as above, changing with the buttonOn state.
ChildComponent property:
... play={this.state.play}
Then, on the button toggle event I wait a half a sec before I change the play state. This is so the button will update it's style right away, and then all the player stuff can run after a tick.
togglePlay = (newValue) => {
this.setState({play: newValue});
}
toggleSpeak = (e) => {
let newValue = !this.state.buttonOn;
this.setState({buttonOn: newValue});
if (this.state.play != newValue) {
setTimeout(function() {
this.togglePlay(newValue);
}.bind(this), 500);
}
Then of course clear the timeout function on dismount:
componentWillUnmount() {
clearTimeout(this.togglePlay);
}