AngularJs - मार्ग परिवर्तन घटना को रद्द करें


88

मैं AngularJs में मार्ग परिवर्तन की घटना को कैसे रद्द करूं?

मेरा वर्तमान कोड है

$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  

}
});

इसके साथ ही यदि सत्यापन विफल हो जाता है, तो कोणीय अगला टेम्पलेट और संबंधित डेटा खींचता है और फिर तुरंत पिछले दृश्य / मार्ग पर वापस आ जाता है। मैं नहीं चाहता कि कोणीय अगला टेम्प्लेट और डेटा खींच सके यदि सत्यापन विफल हो जाता है, तो आदर्श रूप से कोई window.history.back () नहीं होनी चाहिए। मैंने भी event.preventDefault () की कोशिश की, लेकिन कोई फायदा नहीं हुआ।

जवाबों:


184

$routeChangeStartउपयोग के बजाय$locationChangeStart

यहाँ इसके बारे में चर्चा आकुल लोगों से की जा रही है: https://github.com/angular/angular.js/issues/2109

3/6/2018 को संपादित करें आप इसे डॉक्स में देख सकते हैं: https://docs.angularjs.org/api/ng/service/$location#event-$locationChangeStart

उदाहरण:

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

8
इसके साथ समस्या यह है कि मार्ग पैरामीटर संग्रह तक पहुंचने का कोई तरीका नहीं है। यदि आप मार्ग मापदंडों को मान्य करने का प्रयास कर रहे हैं तो यह समाधान अच्छा नहीं है।
KingOfHypocrites

1
कृपया ध्यान दें, जब का उपयोग कर चर सिर्फ एक स्ट्रिंग है और यह किसी भी डेटा (उदाहरण आप कर सकते हैं परिभाषित पहले के लिए उपयोग नहीं करने के लिए उपयोग नहीं होना चाहिए चर)$routeChangeStartnextauthorizedRoles
MyTitle

@KingOfHypocrites आप मार्ग मापदंडों को प्राप्त नहीं कर सकते, लेकिन आप प्राप्त कर सकते हैं $location.path()और$location.search()
Adrian

2
क्या आप रूटस्स्कोप पर ऐसा करना उचित है / कर सकते हैं यदि आप सभी मार्ग परिवर्तनों को ट्रैक करना चाहते हैं? या वहाँ एक और अधिक विकल्प है?
अधिकतम

38

एक और अधिक पूर्ण कोड नमूना, का उपयोग कर $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); 
      });
    }
  );

मैं अपने रूट कंट्रोलर (टॉप लेवल कंट्रोलर) में इसे हुक करने से पूरी तरह से खुश नहीं हूँ। अगर कोई बेहतर पैटर्न है, तो मैं जानना चाहूंगा। मैं कोणीय के लिए नया हूँ :-)


यह मेरे लिए बहुत अच्छा काम किया, हालांकि मैं मूल पोस्टर की तरह अपने मार्ग परिवर्तन को रद्द करने की कोशिश नहीं कर रहा हूं। धन्यवाद!
जिम क्लेज़

4
RootScope के साथ हाँ समस्या यह है कि आपको उस नियंत्रक को हटाने के लिए याद रखना होगा जब आपका नियंत्रक चला जाता है।
लॉस्टि्रन्स्लेरेशन

12

एक समाधान एक 'notAuthorized' घटना को प्रसारित करना है, और स्थान को फिर से बदलने के लिए इसे मुख्य दायरे में पकड़ना है। मुझे लगता है कि यह सबसे अच्छा समाधान नहीं है, लेकिन इसने मेरे लिए काम किया:

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');
                }
            }
        });
    }
]);

और मेरे मुख्य नियंत्रक में:

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

नोट: कोणीय साइट पर इस समस्या के बारे में कुछ चर्चा है, अभी तक हल नहीं हुई है: https://github.com/angular/angular.js/pull/4192

संपादित करें:

टिप्पणी का जवाब देने के लिए, यहाँ LoginService कार्यों के बारे में अधिक जानकारी दी गई है। इसमें 3 कार्य शामिल हैं:

  1. लॉगिन () (नाम भ्रामक है) सर्वर से एक अनुरोध करते हैं कि वह (पहले) लॉग किए गए उपयोगकर्ता के बारे में जानकारी प्राप्त करे। एक और लॉगिन पृष्ठ है जो सर्वर में वर्तमान उपयोगकर्ता स्थिति (बसंतकालीन रूपरेखा का उपयोग करके) को पॉप्युलेट करता है। मेरी वेब सेवाएँ बिल्कुल बेकार नहीं हैं, लेकिन मैंने उस प्रसिद्ध ढांचे को अपनी सुरक्षा को संभालने देना पसंद किया।
  2. isAuthenticated () बस खोज अगर ग्राहक सत्र डेटा से भरा है, जिसका अर्थ है कि यह पहले (*) प्रमाणित किया गया है
  3. isAuthorized () संभाला पहुंच अधिकार (इस विषय के लिए गुंजाइश से बाहर)।

(*) मार्ग परिवर्तित होने पर मेरा सत्र आबाद है। मैंने खाली होने पर सत्र को आबाद करने के लिए जब () विधि को ओवरराइड किया है।

यहाँ कोड है:

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()प्रथम पृष्ठ लोडिंग पर क्या वापसी होगी ? आप कैसे स्टोर कर रहे हैं currentUser? यदि उपयोगकर्ता पृष्ठ को रीफ्रेश करता है (उपयोगकर्ता को फिर से क्रेडेंशियल की आवश्यकता है) तो क्या होगा?
MyTitle

मैंने अपने मूल उत्तर में LoginService के बारे में अधिक जानकारी जोड़ी। CurrentUser सर्वर द्वारा प्रदान किया जाता है, और मार्ग परिवर्तन किसी भी पृष्ठ को ताज़ा करने के लिए संभालता है, उपयोगकर्ता को फिर से लॉग इन करने की कोई आवश्यकता नहीं है।
ऐस्टरियस

4

इस पर ठोकर खाने वाले किसी भी व्यक्ति के लिए एक पुराना सवाल है, (कम से कम कोणीय 1.4 में) आप ऐसा कर सकते हैं:

 .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
मुझे आश्चर्य है, क्या आप ब्रेसिज़ या "?" के उपयोग के लिए अतिरिक्त शुल्क लेते हैं?
सीएल तेज

6
@ मैथियासजैनसेन। और यह सब बंद करने के लिए, ब्रेसिज़ डबल की गिनती करते हैं, और अर्धविराम ट्रिपल की गिनती करते हैं।
53कोस विंद्रा

1

यह मेरा समाधान है और यह मेरे लिए काम करता है, लेकिन मुझे नहीं पता कि मैं सही तरीके से हूं, क्योंकि मैं वेब प्रौद्योगिकियों के लिए नया हूं।

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
यदि आप अपने उत्तर के बारे में सुनिश्चित नहीं हैं, तो आप किसी प्रश्न का उत्तर कैसे दे सकते हैं?
डेव 1

मुझे यकीन है कि यह काम करता है। मुझे यकीन नहीं है कि यह उचित तरीका है। यदि आपके पास एक बेहतर समाधान है तो मैं इसे देखना चाहूंगा।
अलेक्जेंड्राकिस अलेक्जेंड्रोस

1

मुझे यह एक प्रासंगिक लगा

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()   
    });
});

मेरी पोस्ट भविष्य में किसी एक की मदद कर सकती है।


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
हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें स्पष्टीकरण सहित वास्तव में आपकी पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और वे लोग आपके कोड सुझाव के कारणों को नहीं जान सकते हैं।
dpr

0

यदि आपको $routeChangeStartघटना को बदलने से रोकने की आवश्यकता है (यानी आप अगले मार्ग के आधार पर कुछ ऑपरेशन करना चाहते हैं ), इंजेक्ट करें $routeऔर अंदर $routeChangeStartकॉल करें:

$route.reload()

1
मैं आशान्वित था, लेकिन क्रोम पर कोणीय 1.2.7 में यह जेएस लूप और पेज को जमा देता है।
निक स्पेसक

1
@NickSpacek जिस स्थिति में आप कॉल करते $route.reload()हैं वह अलग होना चाहिए या फिर वही कोड फिर से चल रहा है। यह शर्त के whileसाथ लूप बनाने के बराबर है true
केविन बील

0

बस साझा करने के लिए, मेरे मामले में मैं $ मार्ग परिवर्तन के साथ मार्ग संकल्प में देरी करना चाहता हूं। मुझे एक समथिंग सर्विस मिली है जिसे रूट के रिज़ॉल्यूशन शुरू होने से पहले लोड करना होगा (हां, चैटिंग एप्लिकेशन) इसलिए मुझे इंतजार करने का वादा मिला है। हो सकता है कि मुझे कोई हैक मिल गया हो ... यदि रिज़ॉल्यूशन एक अस्वीकृति वापस करता है, तो मार्ग का रिज़ॉल्यूशन त्रुटि में जाता है। मैंने रिज़ॉल्यूशन कॉन्फ़िगरेशन को तोड़ दिया है और मैं इसे बाद में ठीक करता हूं।

    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;
        } 
    });
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.