Check current component after timeout - html

I'm in a component called "recoger_success" and I want it to navigate to the home component after 10 seconds after clicking a button that has countdown() linked to it. The problem is that if I navigate to another component before the timeout gets to 0 then after the 10 seconds it doesn't matter in which component I am, it will always go to home component. I don't want this I want it only to go to the home component if the user is still on the timeout component otherwise ignore it..
I have tryed this to know the url of the actual component but it doesn't work..
countdown(){
setTimeout(() => {
if (this.route.snapshot.url.toString() == 'recoger_success'){
this.router.navigate([""]);
}
}, 10000);
}
apreciate any help.

Assign timeout to a variable and at the time you manually exist the page, clear the timeout
countdown(){
this.timeout = setTimeout(() => {
if (this.route.snapshot.url.toString() == 'recoger_success'){
this.router.navigate([""]);
}
}, 10000);
}
function myStopFunction() {
clearTimeout(this.timeout);
}

You need to bind the setTimeout to a variable.
component.ts
import { Component, OnDestroy } from '#angular/core';
export class Component implements OnDestroy {
countdownTimer: any;
countdown() {
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
}
this.countdownTimer = setTimeout(() => {
if (this.route.snapshot.url.toString() == 'recoger_success') {
this.router.navigate([""]);
}
}, 10000);
}
ngOnDestroy() {
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
}
}
}

Related

How do I delay Angular doCheck execution until user's value is fully entered into input?

I am using the follow doCheck() method to determine if the user's input has changed before processing it.
ngDoCheck() {
if (this.filter.price !== this.oldPrice) {
// this.changeDetected = true;
console.log(`DoCheck: Price changed to "${this.filter.price}" from
"${this.oldPrice}"`);
this.oldPrice = this.filter.price
}
}
The problem is ngDoCheck is called for each individual digit the user enters. I prefer to have the user complete their input before processing it like is done using debounceTime in rxjs.
If it is user input coming from a FormControl I would advise subscribing to its valueChanges observable with a debounceTime operator instead. But if you insist you can also use each call of the ngDoCheck to place the next value into your own observable:
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
class YourComponent {
private changeSubject = new Subject();
ngOnInit() {
this.changeSubject.pipe(
distinctUntilChanged(),
debounceTime(400)
).subscribe( value => {
console.log('debounced value:', value);
});
}
ngDoCheck() {
this.changeSubject.next(this.filter.price);
}
}
Use changes instead of a lifecycle hook.
HTML:
<input (change)="change($event)">
component:
change(newValue) {
console.log(newValue);
}

ng-recaptcha tag <recaptcha> causes error "zone.js: Unhandled Promise rejection" when route changes

I'm using "ng-recaptcha" on Angular component. Im using inside a form like this:
<form class="form-contact"
[formGroup]="contactForm"
#formDirective="ngForm"
(ngSubmit)="sendMessage(contactForm, formDirective)">
<re-captcha class="recaptcha"
formControlName="captcha"
siteKey="mysitekey">
</re-captcha>
</form>
Then I send the form to component:
export class AboutComponent implements OnInit, OnDestroy {
contactForm: FormGroup;
captchaResponse: string;
private emailSubscription: Subscription;
constructor(private emailService: EmailService) { }
ngOnInit() {
this.contactForm = new FormGroup({
captcha: new FormControl('', Validators.required)
});
}
ngOnDestroy(): void {
if (this.emailSubscription) { this.emailSubscription.unsubscribe(); }
}
sendMessage(contactForm: FormGroup, formDirective: FormGroupDirective) {
if (contactForm.valid) {
this.emailSubscription = this.emailService.sendEmail(contactForm.value)
.subscribe((response: ApiResponse) => {
if (response.success) {
console.log(response.message);
formDirective.resetForm();
contactForm.reset();
} else {
this.alertService.error(response.message);
}
}, (error: HttpErrorResponse) => {
console.log({status: error.status, error: error.error});
this.alertService.error('Error sending message. Please try again later or send a direct message.');
}
);
}
}
}
Everything seems to be working fine. However, when route changes (ex. user goes to another page) and the AboutComponent is rendered again, an error pops up: Unhandled Promise rejection: timeout ; Zone: <root> ; Task: Promise.then ; Value: timeout undefined. I'm 99% sure it's caused by <re-captcha> tag because error doesn't show up after removing the tag. Is there a way to render a captcha without errors when route changes (and captcha reloads after im back to component)?
Link to Stackblitz: stackblitz
This is a temporary and pretty bad fix but it worked for me
// somewhere in your "main.ts" or "app.component.ts"
import { RecaptchaComponent } from 'ng-recaptcha';
RecaptchaComponent.prototype.ngOnDestroy = function() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
Read More: https://github.com/DethAriel/ng-recaptcha/issues/123#issuecomment-426112101

change class of an element with media query ,angular 4

want to change a class of an element when the width of browser changes
have that in my .ts
matchMedia('(max-width: 400px)').addListener((mql => {
if (mql.matches) {
this.myclass = 'toggled';
}
}));
and in the html somthing like that:
<app-side-bar [ngClass]="myclass"></app-side-bar>
value of 'myclass' is changed but the HTML element(app-side-bar) is not getting updated -what am I missing here?
Because Angular does keep track of the the event that occurs when the browser size changes, it wont detect the change. You have to trigger it yourself:
You can do this by warpping the code inside NgZone:
import { NgZone } from '#angular/core';
// Inject NgZone in your constructor:
constructor(private zone: NgZone) {
}
// Run the code that changes state inside the zone
matchMedia('(max-width: 400px)').addListener((mql => {
if (mql.matches) {
this.zone.run(() => {
this.myclass = 'toggled';
});
}
}));

How to remove loader when entering escape in react?

I need to come out from page after entering escape button , when the page takes much time for loading. I need to exit that loading when it takes longer time
For loading I am using
dispatcher.dispatch({
type:'Loader',
showLoader: true
})
You will have to add an event listener i.e. keyup or keydown. When any key is pressed, just compare its keyCode with escape button's keycode i.e. 27.
In react, event listener should be added in componentDidMount and removed in componentWillUnmount.
Here is an example. You can modify logic according to your requirements.
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
loading: true,
}
this.onKeyUp = this.onKeyUp.bind(this)
}
componentDidMount() {
document.body.addEventListener('keyup', this.onKeyUp)
}
componentWillUnmount() {
document.body.removeEventListener('keyup', this.onKeyUp)
}
onKeyUp(e) {
if (/27/.test(e.keyCode)) {
this.setState({ loading: false })
}
}
render() {
if (this.state.loading) {
return <div>Loading</div>
}
return <div>Loaded</div>
}
}
Hope it helps.

react-router root onChange to replace path infinite

It seems if I change path in root onEnter or onChange hook, the url will change infinite. But if I change path in child routes, it will work. Actually I want to handle the authentication in one place, otherwise every child route should handle the same logic.
{
path: '/',
onChange: function(prevState, nextState, replace, callback) {
if(!logined) {
replace('login');
}
},
childRoutes: [
....
]
}
It changes infinitly because onChange invokes on replace
try
onChange: function(prevState, {location:{pathname:next}}, replace)=> {
if(!logined && next !== '/login') {
replace('/login');
}
}
also to handle the authentication in one place, you can use HOC, something like that
const CheckAuth = (isLogined, redirectPath) => Component =>
class CheckAuth extends React.Component {
componentWillUpdate(nextProps, nextState){
//Check auth on change
this.checkAuth(nextProps);
}
componentWillMount(){
//Check auth on enter
this.checkAuth(this.props);
}
checkAuth({location}){
if(!isLogined && location.pathname!==redirectPath) {
browserHistory.replace(redirectPath);
}
}
render(){
return (<Component {...this.props}/>);
}
};
and App component
class App extends React.Component { ... }
export default CheckAuth(isLogined,'/login')(App);
also, there is a way with redux-auth-wrapper