AngularJs - rota değiştirme olayını iptal et


88

AngularJs'de rota değişikliği olayını nasıl iptal ederim?

Mevcut kodum

$rootScope.$on("$routeChangeStart", function (event, next, current) {

// do some validation checks
if(validation checks fails){

    console.log("validation failed");

    window.history.back(); // Cancel Route Change and stay on current page  

}
});

bununla, doğrulama başarısız olsa bile Angular, sonraki şablonu ve ilişkili verileri çeker ve ardından hemen önceki görünüme / rotaya geri döner. Doğrulama başarısız olursa sonraki şablonu ve verileri açısal olarak almak istemiyorum, ideal olarak window.history.back () olmamalıdır. Event.preventDefault () 'u bile denedim ama kullanmadım.

Yanıtlar:


184

Yerine $routeChangeStartkullanımı$locationChangeStart

İşte angularjs adamlarından bu konudaki tartışma: https://github.com/angular/angular.js/issues/2109

Edit 3/6/2018 Bunu şu belgelerde bulabilirsiniz: https://docs.angularjs.org/api/ng/service/$location#event-$locationChangeStart

Misal:

$scope.$on('$locationChangeStart', function(event, next, current) {
    if ($scope.form.$invalid) {
       event.preventDefault();
    }
});

8
Bununla ilgili sorun, rota parametreleri koleksiyonuna erişmenin bir yolu olmamasıdır. Rota parametrelerini doğrulamaya çalışıyorsanız, bu çözüm işe yaramaz.
KingOfHypocrites

1
Lütfen $routeChangeStart, nextdeğişken kullanımının sadece bir dizge olduğunu ve herhangi bir veri içeremeyeceğini unutmayın (örneğin, daha önce tanımlanan authorizedRolesdeğişkene
erişemezsiniz

@KingOfHypocrites rota parametrelerini alamazsınız, ancak alabilirsiniz $location.path()ve$location.search()
Design by Adrian

2
Tüm rota değişikliklerini izlemek istiyorsanız, bunu rootScope'ta yapmanız tavsiye edilir mi / tavsiye edilir mi? Yoksa daha lezzetli bir alternatif var mı?
maxm

38

Kullanarak daha eksiksiz bir kod örneği $locationChangeStart

// assuming you have a module called app, with a 
angular.module('app')
  .controller(
    'MyRootController',
    function($scope, $location, $rootScope, $log) {
      // your controller initialization here ...
      $rootScope.$on("$locationChangeStart", function(event, next, current) { 
        $log.info("location changing to:" + next); 
      });
    }
  );

Bunu kök denetleyicime (üst düzey denetleyici) bağlamaktan tamamen memnun değilim. Daha iyi bir model varsa bilmek isterim. Angular'da yeniyim :-)


Orijinal posterdeki gibi rota değişikliğimi iptal etmeye çalışmama rağmen, bu benim için harika çalıştı. Teşekkürler!
Jim Clouse

4
Evet, rootScope ile ilgili sorun, denetleyiciniz gittiğinde bu işleyicinin bağlantısını çözmeyi hatırlamanız gerektiğidir.
lostintranslation

12

Bir çözüm, "notAuthorized" olayını yayınlamak ve konumu yeniden değiştirmek için ana kapsamda yakalamaktır. Bunun en iyi çözüm olmadığını düşünüyorum ama benim için çalıştı:

myApp.run(['$rootScope', 'LoginService',
    function ($rootScope, LoginService) {
        $rootScope.$on('$routeChangeStart', function (event, next, current) {
            var authorizedRoles = next.data ? next.data.authorizedRoles : null;
            if (LoginService.isAuthenticated()) {
                if (!LoginService.isAuthorized(authorizedRoles)) {
                    $rootScope.$broadcast('notAuthorized');
                }
            }
        });
    }
]);

ve Ana Denetleyicimde:

    $scope.$on('notAuthorized', function(){
        $location.path('/forbidden');
    });

Not: Açısal sitede bu sorunla ilgili henüz çözülmemiş bazı tartışmalar var: https://github.com/angular/angular.js/pull/4192

DÜZENLE:

Yorumu yanıtlamak için, LoginService çalışmaları hakkında daha fazla bilgi burada. 3 işlevi içerir:

  1. login () (ad yanıltıcıdır) (önceden) oturum açmış kullanıcı hakkında bilgi almak için sunucuya bir istekte bulunun. Sunucudaki mevcut kullanıcı durumunu (SpringSecurity çerçevesini kullanarak) dolduran başka bir oturum açma sayfası daha vardır. Web Servislerim gerçek anlamda vatansız değildir, ancak güvenliğimi bu ünlü çerçevenin üstlenmesine izin vermeyi tercih ettim.
  2. isAuthenticated () sadece istemci Oturumunun verilerle dolu olup olmadığını araştırır, bu da daha önce doğrulandığı anlamına gelir (*)
  3. isAuthorized () erişim haklarını işledi (bu konu için kapsam dışında).

(*) Rota değiştiğinde Oturumum doldurulur. Oturumu boşken doldurmak için when () yöntemini geçersiz kıldım.

İşte kod:

services.factory('LoginService', ['$http', 'Session', '$q',
function($http, Session, $q){
    return {
        login: function () {
            var defer = $q.defer();
            $http({method: 'GET', url: restBaseUrl + '/currentUser'})
                .success(function (data) {
                    defer.resolve(data);
                });
            return defer.promise;
        },
        isAuthenticated: function () {
            return !!Session.userLogin;
        },
        isAuthorized: function (authorizedRoles) {
            if (!angular.isArray(authorizedRoles)) {
                authorizedRoles = [authorizedRoles];
            }

            return (this.isAuthenticated() &&  authorizedRoles.indexOf(Session.userRole) !== -1);
        }
    };
}]);

myApp.service('Session', ['$rootScope',
    this.create = function (userId,userLogin, userRole, userMail, userName, userLastName, userLanguage) {
        //User info
        this.userId = userId;
        this.userLogin = userLogin;
        this.userRole = userRole;
        this.userMail = userMail;
        this.userName = userName;
        this.userLastName = userLastName;
        this.userLanguage = userLanguage;
    };

    this.destroy = function () {
        this.userId = null;
        this.userLogin = null;
        this.userRole = null;
        this.userMail = null;
        this.userName = null;
        this.userLastName = null;
        this.userLanguage = null;
        sessionStorage.clear();
    };

    return this;
}]);

myApp.config(['$routeProvider', 'USER_ROLES', function ($routeProvider, USER_ROLES) {
    $routeProvider.accessWhen = function (path, route) {
        if (route.resolve == null) {
            route.resolve = {
                user: ['LoginService','Session',function (LoginService, Session) {
                    if (!LoginService.isAuthenticated())
                        return LoginService.login().then(function (data) {
                            Session.create(data.id, data.login, data.role, data.email, data.firstName, data.lastName, data.language);
                            return data;
                        });
                }]
            }
        } else {
            for (key in route.resolve) {
                var func = route.resolve[key];
                route.resolve[key] = ['LoginService','Session','$injector',function (LoginService, Session, $injector) {
                    if (!LoginService.isAuthenticated())
                        return LoginService.login().then(function (data) {
                            Session.create(data.id, data.login, data.role, data.email, data.firstName, data.lastName, data.language);
                            return func(Session, $injector);
                        });
                    else
                        return func(Session, $injector);
                }];
            }
        }
    return $routeProvider.when(path, route);
    };

    //use accessWhen instead of when
    $routeProvider.
        accessWhen('/home', {
            templateUrl: 'partials/dashboard.html',
            controller: 'DashboardCtrl',
            data: {authorizedRoles: [USER_ROLES.superAdmin, USER_ROLES.admin, USER_ROLES.system, USER_ROLES.user]},
            resolve: {nextEvents: function (Session, $injector) {
                $http = $injector.get('$http');
                return $http.get(actionBaseUrl + '/devices/nextEvents', {
                    params: {
                        userId: Session.userId, batch: {rows: 5, page: 1}
                    },
                    isArray: true}).then(function success(response) {
                    return response.data;
                });
            }
        }
    })
    ...
    .otherwise({
        redirectTo: '/home'
    });
}]);

LoginService.isAuthenticated()İlk sayfa yüklemesinde ne dönüşü söyler misiniz ? Nasıl depoluyorsun currentUser? Kullanıcı sayfayı yenilerse ne olur (kullanıcının kimlik bilgilerini yeniden girmesi gerekir)?
MyTitle

Orijinal cevabıma LoginService hakkında daha fazla bilgi ekledim. CurrentUser sunucu tarafından sağlanır ve rota değişikliği herhangi bir sayfa yenilemesini ele alır, kullanıcının tekrar oturum açmasına gerek yoktur.
Asterius

4

Bunun üzerine tökezleyen herkes için eski bir sorudur (en azından açısal 1.4'te) bunu yapabilirsiniz:

 .run(function($rootScope, authenticationService) {
        $rootScope.$on('$routeChangeStart', function (event, next) {
            if (next.require == undefined) return

            var require = next.require
            var authorized = authenticationService.satisfy(require);

            if (!authorized) {
                $rootScope.error = "Not authorized!"
                event.preventDefault()
            }
        })
      })

6
Merak ediyorum, diş teli veya ";" kullanımı için fazladan ücret alıyor musunuz?
cel sharp

6
@MatthiasJansen tabii ki. Üstelik, parantezler çift sayılır ve noktalı virgül üç katına çıkar.
Ákos Vandra

1

Bu benim çözümüm ve benim için işe yarıyor ancak doğru yolda olup olmadığımı bilmiyorum çünkü web teknolojilerinde yeniyim.

var app = angular.module("app", ['ngRoute', 'ngCookies']);
app.run(function($rootScope, $location, $cookieStore){
$rootScope.$on('$routeChangeStart', function(event, route){
    if (route.mustBeLoggedOn && angular.isUndefined($cookieStore.get("user"))) {
        // reload the login route
        jError(
             'You must be logged on to visit this page',
             {
               autoHide : true,
               TimeShown : 3000,
               HorizontalPosition : 'right',
               VerticalPosition : 'top',
               onCompleted : function(){ 
               window.location = '#/signIn';
                 window.setTimeout(function(){

                 }, 3000)
             }
        });
    }
  });
});

app.config(function($routeProvider){
$routeProvider
    .when("/signIn",{
        controller: "SignInController",
        templateUrl: "partials/signIn.html",
        mustBeLoggedOn: false
});

2
Cevabınızdan emin değilseniz bir soruyu nasıl cevaplayabilirsiniz?
deW1

Eminim işe yarar. Bunun doğru yol olduğundan emin değilim. Daha iyi bir çözümünüz varsa görmek isterim.
Alexandrakis alexandros

1

bunu alakalı buldum

var myApp = angular.module('myApp', []);

myApp.run(function($rootScope) {
    $rootScope.$on("$locationChangeStart", function(event, next, current) { 
        // handle route changes  
$rootScope.error = "Not authorized!"
                event.preventDefault()   
    });
});

Gönderim gelecekte birine yardımcı olabilir.


1
var app=angular
    .module('myapp', [])
    .controller('myctrl', function($rootScope) {
        $rootScope.$on("locationChangeStart", function(event, next, current) {
        if (!confirm("location changing to:" + next)) { 
            event.preventDefault();
        }
    })
});

2
Bu kod parçacığı soruyu çözebilirken, bir açıklama eklemek, yayınınızın kalitesini artırmaya gerçekten yardımcı olur. Gelecekte okuyucular için soruyu yanıtlayacağınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceklerini unutmayın.
dpr

0

$routeChangeStartOlay sırasında rotanın değişmesini durdurmanız gerekirse (yani , sonraki rotaya göre bazı işlemler gerçekleştirmek istiyorsanız ), enjekte $routeve dahili $routeChangeStartarama:

$route.reload()

1
Umutluydum, ancak Chrome'daki Angular 1.2.7'de bu bir JS döngüsüne neden oluyor ve sayfa donuyor.
Nick Spacek

1
@NickSpacek Aradığınız koşul $route.reload()farklı olmalı, yoksa aynı kodu tekrar çalıştırıyor. Bu, koşul olarak bir whiledöngü oluşturmaya eşdeğerdir true.
Kevin Beal

0

Sadece paylaşmak için, benim durumumda rota çözümlemesini $ routeChangeStart ile ertelemek istiyorum . Rota çözünürlüğü başlamadan önce yüklenmesi gereken bir SomethingService hizmetim var (evet, konuşkan uygulama) bu nedenle beklemem gereken bir söz var. Belki bir hack buldum ... Bir çözüm bir ret döndürürse, rotanın çözümü hata verir. Çözümleme yapılandırmasını bozdum ve daha sonra düzeltiyorum.

    var rejectingResolve = {
        cancel: function ($q){
            // this will cancel $routeChangeStart
            return $q.reject();
        }
    }
    
    $rootScope.$on("$routeChangeStart", function(event, args, otherArgs) {
        var route = args.$$route,
            originalResolve = route.resolve;
    
        if ( ! SomethingService.isLoaded() ){

            SomethingService.load().then(function(){
                // fix previously destroyed route configuration
                route.resolve = originalResolve;
                
                $location.search("ts", new Date().getTime());
                // for redirections
                $location.replace();
            });

            // This doesn't work with $routeChangeStart: 
            // we need the following hack
            event.preventDefault();
            
            // This is an hack! 
            // We destroy route configuration, 
            // we fix it back when SomethingService.isLoaded
            route.resolve = rejectingResolve;
        } 
    });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.