Base solution for your next web application
Open Closed

CanDeactivate shows a spinner on top of modal #12348


User avatar
0
hra created

Hi Team,

We're working through updating our aspnet zero project

We've noticed that the alert box that is supposed to show when navigating away from page with unsaved changes shows underneath the loading spinner (see screenshot below)

chrome_7DqTujJJxx.jpg

Our code looks like this:

import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from "@angular/router";
import { Injectable } from '@angular/core';
import { Observable, Subject } from "rxjs";
import { MessageService, LocalizationService } from "abp-ng2-module";
import { AppConsts } from "../../AppConsts";

@Injectable()
export class CanDeactivateUnsaved implements CanDeactivate {
    localizationSourceName = AppConsts.localization.defaultLocalizationSourceName;

    constructor(
        private localization: LocalizationService,
        private _message: MessageService
    ) { }

    canDeactivate(
        component: ICanSaveChanges,
        currentRoute: ActivatedRouteSnapshot,
        currentState: RouterStateSnapshot,
        nextState: RouterStateSnapshot
    ): Observable | Promise | boolean | UrlTree {
        if (component.hasChanges) {
            return new Promise((resolve, reject) => {
                this._message.confirm(
                    this.l('UnsavedChanges'),
                    this.l('Warning'),
                    isConfirmed => {
                        resolve(isConfirmed);
                        //if (isConfirmed)
                        //    component.Save();
                    }
                );
            });
        }
        return true;
    }
}

The route change happens regardless of whether "cancel" or "save" is selected in the confirmation modal:

image.png


1 Answer(s)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @hra

    Ensure that the modal is only displayed after the spinner has been dismissed, or at least manages its own stacking context. You can do this by waiting for the spinner to finish before showing the modal.

    In this case, the loading is coming from the PrimeNG table. You may need to check the state here as well. After using the showLoadingIndicator() method, you should call the hideLoadingIndicator() method in the finalize block.

    When the user attempts to navigate away without saving changes, you can call the hideLoadingIndicator() method for the relevant PrimeNG table. Alternatively, we can use the example code below. The approach would be to use the hideLoadingIndicator() method for the PrimeNG table.

    Example Code

    import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from "@angular/router";
    import { Injectable } from '@angular/core';
    import { Observable } from "rxjs";
    import { MessageService, LocalizationService } from "abp-ng2-module";
    import { AppConsts } from "../../AppConsts";
    import { NgxSpinnerService } from 'ngx-spinner';
    
    @Injectable()
    export class CanDeactivateUnsaved implements CanDeactivate {
        localizationSourceName = AppConsts.localization.defaultLocalizationSourceName;
    
        constructor(
            private localization: LocalizationService,
            private _message: MessageService,
            private spinnerService: NgxSpinnerService
        ) { }
    
        canDeactivate(
            component: ICanSaveChanges,
            currentRoute: ActivatedRouteSnapshot,
            currentState: RouterStateSnapshot,
            nextState: RouterStateSnapshot
        ): Observable | Promise | boolean | UrlTree {
            if (component.hasChanges) {
                this.spinnerService.hide(); // Hide the spinner before showing the modal
                return new Promise((resolve, reject) => {
                    this._message.confirm(
                        this.l('UnsavedChanges'),
                        this.l('Warning'),
                        isConfirmed => {
                            this.spinnerService.show(); // Show the spinner again after the modal is closed
                            resolve(isConfirmed);
                            //if (isConfirmed)
                            //    component.Save();
                        }
                    );
                });
            }
            return true;
        }
    }