Search code examples
javascriptangularjsonbeforeunloadngroute

Show confirmation modal before calling $routeChangeStart in AngularJs like window onbeforeunload


Im able to show a confirmation modal once route starts to change, if users selects to stay my route does not change, it stays to the original route, but loads the form directives again, which causes form to loss all its checkbox, input values. It gets reset to defaults.

If a user closes the page, i'm able to show confirmation modal, also the form state does not change. All values are retained.

Below is my code: also, please note Im also injecting a resolve for all routes by default (this Angular : How use one resolve for all the routes of my application)

After that im calling .run()

$rootScope.$on('$routeChangeStart', function (event, newUrl, oldUrl) {
            //isLoggedIn also check URL params
            if (!Auth.isLoggedIn()) {
                $window.location.href = Auth.getLoginUrl();
            }

            ////unsaved modal start
            if ($rootScope.unsaved) {

                ngDialog.open({
                    className: 'ngdialog-theme-default unsaved-modal',
                    template: 'scripts/core/commonmodal/tplUnsavedModal.html',
                    controller: [function OpenDialogContainer() {
                        var modal = this;
                        modal.message = 'You have some unsaved changes. Do you want to leave this page?';
                        modal.stop = function () {
                            modal.processing = true;
                            ngDialog.close();
                            $rootScope.$broadcast('$routeChangeSuccess');
                        };
                        modal.continue = function () {
                            modal.processing = true;
                            ngDialog.close();
                            $rootScope.unsaved = false;
                            $location.path(newUrl.$$route.originalPath); //Go to page they're interested in
                        };
                    }],
                    controllerAs: 'modal'
                });
                //prevent navigation by default since we'll handle it
                //once the user selects a dialog option
                event.preventDefault();
            }

        });

Im setting $rootScope.unsaved = true if form is NOT $pristine and NOT $submitted

As you can see in the below gifvideo, on stay the route runs the controller function again. Instead what I wanted was a window onbeforeunload alike effect.

http://recordit.co/g5T9wWkDry.gif


Solution

  • I fixed it just by removing this line $rootScope.$broadcast('$routeChangeSuccess'); also, instead I made a directive.

    link: function($scope) {
                    var message = 'You have some unsaved changes. Do you want to leave this page?';
                    $window.onbeforeunload = function(){
                        if ($scope.unsavedChanges) {
                            return 'You have some unsaved changes. Do you want to leave this page?';
                        }
                    };
                    var $routeChangeStartUnbind = $rootScope.$on('$routeChangeStart', function(event, newUrl) {
                        if ($scope.unsavedChanges) {
                            $rootScope.pageloaded = true;//prevent loading icon
                            ngDialog.open({
                                appendClassName: 'unsaved-modal',
                                template: 'scripts/core/commonmodal/tplUnsavedModal.html',
                                controller: [function OpenDialogContainer() {
                                    var modal = this;
                                    modal.message = message;
                                    modal.stop = function () {
                                        modal.processing = true;
                                        ngDialog.close();
                                    };
                                    modal.continue = function () {
    
                                        modal.processing = true;
                                        ngDialog.close();
                                        $routeChangeStartUnbind();
                                        $location.path(newUrl.$$route.originalPath); //Go to page they're interested in
                                        $rootScope.pageloaded = false;
                                        $scope.unsavedChanges = false;
                                        $window.location.reload();//$route.reload() does not reload services
                                    };
                                }],
                                controllerAs: 'modal'
                            });
                            //prevent navigation by default since we'll handle it
                            //once the user selects a dialog option
                            event.preventDefault();
                        }
                    });
    
                    $scope.$on('$destroy', function() {
                        window.onbeforeunload = null;
                        $routeChangeStartUnbind();
                    });
                }