我正在尝试使用ng-switch和ng-include。问题在于ng-init和整个控制器块在任何包含更改时重新呈现。
在login_form.html中,当用户登录时,我在LoginCtrl中设置isLoggedIn = true。但是这会导致重新呈现下面的完整html,这会再次导致ng-init。
如何避免这种循环?
<div ng-controller="LoginCtrl" ng-init="isLoggedIn = false" class="span4 pull-right">
<div ng-switch on="isLoggedIn">
<div ng-switch-when="false" ng-include src="'login_form.html'"></div>
<div ng-switch-when="true" ng-include src="'profile_links.html'"></div>
</div>
</div>
以下是登录表单的HTML -
<form class="form-inline">
<input type="text" placeholder="Email" ng-model="userEmail" class="input-small"/>
<input type="password" placeholder="Password" ng-model="userPassword" class="input-small"/>
<button type="submit" ng-click="login(userEmail, userPassword)" class="btn">Sign In</button>
</form>
以下是控制器 -
angularApp.controller('LoginCtrl', function($scope, currentUser){
$scope.loginStatus = function(){
return currentUser.isLoggedIn();
};
/* $scope.$on('login', function(event, args) {
$scope.userName = args.name;
});
$scope.$on('logout', function(event, args) {
$scope.isLoggedIn = false;
});*/
$scope.login = function(email, password){
currentUser.login(email, password);
};
$scope.logout = function(){
currentUser.logout();
};
});
Blow就是服务 -
angularApp.factory('currentUser', function($rootScope) {
// Service logic
// ...
//
var allUsers = {"rob@gmail.com": {name: "Robert Patterson", role: "Admin", email: "rob@gmail.com", password: "rob"},
"steve@gmail.com":{name: "Steve Sheldon", role: "User", email: "steve@gmail.com", password: "steve"}}
var isUserLoggedIn = false;
// Public API here
return {
login: function(email, password){
var user = allUsers[email];
var storedPass = user.password;
if(storedPass === password){
isUserLoggedIn = true;
return true;
}
else
{
return false;
}
},
logout: function(){
$rootScope.$broadcast('logout');
isUserLoggedIn = false;
},
isLoggedIn: function(){
return isUserLoggedIn;
}
};
});
答案 0 :(得分:38)
我相信你的问题是原型继承工作方式的结果。 ng-include创建自己的子范围。在子作用域中分配原始值会在该作用域上创建一个新属性,用于遮蔽/隐藏父属性。
我猜测在login_form.html中,当用户登录时,您会执行以下操作:
<a ng-click="isLoggedIn=true">login</a>
在将isLoggedIn设置为true之前,这就是您的示波器的样子:
将isLoggedIn设置为true后,这就是您的示波器的样子:
希望这些照片能说清楚为什么这会给你带来麻烦。
有关为什么原型继承以原始方式工作的更多信息,请参阅What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
如上所述,您有三种解决方案:
<a ng-click="$parent.isLoggedIn=true">login</a>
更新:在审核HTML时,您实际上可能有两个级别的子范围,因为ng-switch和ng-include都创建了自己的范围。所以,图片需要一个孙子范围,但三个解决方案是相同的...除了#2,你需要使用$ parent。$ parent.isLoggedIn - 丑陋。所以我建议选择1或3。
Update2 :@ murtaza52在问题中添加了一些代码...从控制器中删除ng-init="isLoggedIn = false"
(您的服务通过其isUserLoggedIn
变量管理登录状态)在控制器中打开loginStatus():<div ng-switch on="loginStatus()">
。
答案 1 :(得分:3)
我有working example。技巧是要评估的范围变量必须是对象,而不是基本类型。看起来$scope.$watch()
没有正确地观察原始类型(这是一个错误)。 jsFiddle有一个带有两个子控制器的父控制器,但它也只能用于一个(父)控制器。
<强> HTML:强>
<div ng-controller="LoginCheckCtrl">
<div ng-switch on="user.login">
<div ng-switch-when="false" ng-include="'login'"></div>
<div ng-switch-when="true" ng-include="'logout'"></div>
</div>
</div>
<强>控制器:强>
function LoginCheckCtrl($scope) {
$scope.user = {
login: false
};
}
注意:这也只适用于一个控制器:
function LoginCheckCtrl($scope) {
$scope.user = {
login: false
};
$scope.login = function() {
console.log($scope.user.login ? 'logged in' : 'not logged in');
$scope.user.login = true;
};
$scope.logout = function() {
console.log($scope.user.login ? 'logged in' : 'not logged in');
$scope.user.login = false;
};
}
答案 2 :(得分:0)
您可以存储在父作用域中重新初始化控制器所需的状态。我认为甚至在$ rootScope上放置isLoggedIn也不奇怪。
另外,你可以在控制器内部初始化,在这种情况下会更干净(但它不能解决你的问题)。