Skip to content
Advertisement

How to hold alert box on the page in case of reloading or changing route?

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.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement