我正在写一个小的AngularJS应用程序,它有一个登录视图和一个主视图,配置如下:
$routeProvider
.when('/main' , {templateUrl: 'partials/main.html', controller: MainController})
.when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
.otherwise({redirectTo: '/login'});
我的LoginController检查user/pass组合,并在$rootScope上设置一个属性:
function LoginController($scope, $location, $rootScope) {
$scope.attemptLogin = function() {
if ( $scope.username == $scope.password ) { // test
$rootScope.loggedUser = $scope.username;
$location.path( "/main" );
} else {
$scope.loginError = "Invalid user/pass.";
}
}
一切正常,但如果我访问http://localhost/#/main,我最终绕过了登录屏幕。我想写一些类似于“每当路由改变,如果$rootScope。loggedUser为空,然后重定向到/login"
...
... 等待。我能以某种方式听到路线变化吗?不管怎样,我会把这个问题发布出来,继续寻找。
以下是我的做法,希望对大家有所帮助:
在配置中,我在我想向公众开放的少数路由上设置了一个publicAccess属性(比如登录或注册):
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginCtrl',
publicAccess: true
})
然后在一个运行块中,我在$routeChangeStart事件上设置了一个监听器,它重定向到'/login',除非用户有访问权限或路由是公共可访问的:
angular.module('myModule').run(function($rootScope, $location, user, $route) {
var routesOpenToPublic = [];
angular.forEach($route.routes, function(route, path) {
// push route onto routesOpenToPublic if it has a truthy publicAccess value
route.publicAccess && (routesOpenToPublic.push(path));
});
$rootScope.$on('$routeChangeStart', function(event, nextLoc, currentLoc) {
var closedToPublic = (-1 === routesOpenToPublic.indexOf($location.path()));
if(closedToPublic && !user.isLoggedIn()) {
$location.path('/login');
}
});
})
显然,你可以将条件从isLoggedIn更改为其他任何条件…只是展示了另一种方法。
在深入研究了一些文档和源代码之后,我想我已经让它工作了。也许这对其他人有用?
我在我的模块配置中添加了以下内容:
angular.module(...)
.config( ['$routeProvider', function($routeProvider) {...}] )
.run( function($rootScope, $location) {
// register listener to watch route changes
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
if ( $rootScope.loggedUser == null ) {
// no logged user, we should be going to #login
if ( next.templateUrl != "partials/login.html" ) {
// not going to #login, we should redirect now
$location.path( "/login" );
}
}
});
})
有一件事似乎很奇怪,我必须测试部分名称(login.html),因为“next”Route对象没有url或其他东西。也许有更好的办法?
这里可能有一个更优雅、更灵活的解决方案,它具有“resolve”配置属性和“promises”,可以根据数据在路由和路由规则上最终加载数据。
你在路由配置中的“resolve”和函数加载和检查数据中指定一个函数,做所有重定向。如果你需要加载数据,你返回一个承诺,如果你需要重定向-拒绝承诺之前。
所有细节都可以在$routerProvider和$q文档页找到。
'use strict';
var app = angular.module('app', [])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: "login.html",
controller: LoginController
})
.when('/private', {
templateUrl: "private.html",
controller: PrivateController,
resolve: {
factory: checkRouting
}
})
.when('/private/anotherpage', {
templateUrl:"another-private.html",
controller: AnotherPriveController,
resolve: {
factory: checkRouting
}
})
.otherwise({ redirectTo: '/' });
}]);
var checkRouting= function ($q, $rootScope, $location) {
if ($rootScope.userProfile) {
return true;
} else {
var deferred = $q.defer();
$http.post("/loadUserProfile", { userToken: "blah" })
.success(function (response) {
$rootScope.userProfile = response.userProfile;
deferred.resolve(true);
})
.error(function () {
deferred.reject();
$location.path("/");
});
return deferred.promise;
}
};
说俄语的人habr上有一篇文章“ВариантусловногораутингавAngularJS。”