I need to maintain an alert box on the Registration
page indicating the user has registered successfully. However, by redirecting to the Login
form this box disappears, because the page refreshes.
I utilize the Alert
component to manage this scenario. All of the features work flawlessly but this problem really makes me confused. I shared my code and hope you assist me in getting to the root of this predicament.
alert.component.ts
import { Component, OnInit, OnDestroy, Input } from '@angular/core'; import { Router, NavigationStart } from '@angular/router'; import { Subscription } from 'rxjs'; import { Alert, AlertType } from 'src/app/_models/alert'; import { AlertService } from 'src/app/_services/alert.service'; @Component({ selector: 'alert', templateUrl: 'alert.component.html', styleUrls: ['./alert.component.scss'] }) export class AlertComponent implements OnInit, OnDestroy { @Input() id = 'default-alert'; @Input() fade = true; alerts: Alert[] = []; alertSubscription: Subscription; routeSubscription: Subscription; constructor(private router: Router, private alertService: AlertService) { } ngOnInit() { // subscribe to new alert notifications this.alertSubscription = this.alertService.onAlert(this.id) .subscribe(alert => { // clear alerts when an empty alert is received if (!alert.message) { // filter out alerts without 'keepAfterRouteChange' flag this.alerts = this.alerts.filter(x => x.keepAfterRouteChange); // remove 'keepAfterRouteChange' flag on the rest this.alerts.forEach(x => delete x.keepAfterRouteChange); return; } // add alert to array this.alerts.push(alert); setTimeout(() => this.removeAlert(alert), 5000); }); // clear alerts on location change this.routeSubscription = this.router.events.subscribe(event => { if (event instanceof NavigationStart) { this.alertService.clear(this.id); } }); } ngOnDestroy() { // unsubscribe to avoid memory leaks this.alertSubscription.unsubscribe(); this.routeSubscription.unsubscribe(); } removeAlert(alert: Alert) { // check if already removed to prevent error on auto close if (!this.alerts.includes(alert)) return; if (this.fade) { // fade out alert this.alerts.find(x => x === alert).fade = true; // remove alert after faded out setTimeout(() => { this.alerts = this.alerts.filter(x => x !== alert); }, 250); } else { // remove alert this.alerts = this.alerts.filter(x => x !== alert); } } cssClass(alert: Alert) { if (!alert) return; const classes = ['toast']; const alertTypeClass = { [AlertType.Success]: 'toast-success', [AlertType.Error]: 'toast-error', [AlertType.Info]: 'toast-info', [AlertType.Warning]: 'toast-warning' } classes.push(alertTypeClass[alert.type]); if (alert.fade) { classes.push('fade'); } return classes.join(' '); } }
alert.service.ts
import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; import { filter } from 'rxjs/operators'; import { Alert, AlertType } from '../_models/alert'; @Injectable({ providedIn: 'root' }) export class AlertService { private subject = new Subject<Alert>(); private defaultId = 'default-alert'; // enable subscribing to alerts observable onAlert(id = this.defaultId): Observable<Alert> { return this.subject.asObservable().pipe(filter(x => x && x.id === id)); } // convenience methods success(message: string, options?: any) { this.alert(new Alert({ ...options, type: AlertType.Success, message })); } error(message: string, options?: any) { this.alert(new Alert({ ...options, type: AlertType.Error, message })); } info(message: string, options?: any) { this.alert(new Alert({ ...options, type: AlertType.Info, message })); } warn(message: string, options?: any) { this.alert(new Alert({ ...options, type: AlertType.Warning, message })); } // main alert method alert(alert: Alert) { alert.id = alert.id || this.defaultId; this.subject.next(alert); } // clear alerts clear(id = this.defaultId) { this.subject.next(new Alert({ id })); } }
This is a piece of code in which an alert message is called (It should be noted that the keepAfterRouteChange
is set to True):
onSubmit() { this.submitted = true; // reset alerts on submit this.alertService.clear(); // stop here if form is invalid if (this.form.invalid) { return; } this.loading = true; this.accountService .register(this.form.value) .pipe(first()) .subscribe((data) => { this.loading = false; this.submitted = false; if (data.hasError) { this.alertService.error(data.errorMessage); } else { this.alertService.success('Registration successfully completed.', { keepAfterRouteChange: true, }); localStorage.setItem('regCount',JSON.parse(localStorage.getItem('regCount')) + 1); this.router.navigate(['/login']).then(() => { window.location.reload(); }); } }, () => { this.loading = false; this.submitted = false; this.alertService.error('Something went wrong.'); }); }
Advertisement
Answer
Your problem probably comes from window.location.reload();
when window is reloaded all components and services are flushed. Find other ways to clear services if that’s the point this line. Or find other way to store info that alert should be showing (e.g storing the need to show an alert with info and duration in SessionStorage or LocalStorage) – which doesn’t seem like a good idea though. Normally we want to avoid reloading windows – for the same reason, losing all data and forcing the client to reload all resources.