问题描述
我有一个带有navbar指令和基本注册/登录功能的应用程序。 我想在用户登录后更改导航栏上的一些单词(从“注册/登录”到“退出”),但我无法找到最佳(甚至是一种)方式来执行此操作。 我已经尝试将我想要更改的变量/绑定的值设置为在用户登录时更新的工厂,但这不起作用,并且指令不会使用其新值更新。
我的代码附在下面,特定的解决方案是值得赞赏的,但并不是真的有必要,如果有人能指出我正确的方向,如何做到这将是非常有帮助的。
我试过的解决方案:
-
工厂
- 设置绑定变量等于更新的工厂变量
- 设置绑定变量等于这些变量的getter语句的输出
-
饼干(宁愿避免,除非有人说服我这是解决这个问题的好方法)
- 设置绑定变量等于cookie中的值
不幸的是,这些都不会导致指令变量动态更新。 我觉得解决方案很简单,但我想不出我应该做什么。
潜在解决方案
- 使用路由,例如在用户登录时将视图从一个导航栏更改为另一个导航栏,尽管这看起来非常笨重
- $ rootScope(不完全确定如何使用它,我猜这是错误的用途)
navbar.html
<nav class="navbar navbar-static-top navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#/">
<span class="glyphicon glyphicon-star"></span> Home
</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6">
<ul class="nav navbar-nav">
<li><a ui-sref="message">Message</a></li>
<li><a ui-sref="list">User List</a></li>
<li><a ui-sref="schedule">Schedule</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a ng-href="{{ vm.accountStatusLink }}">{{ vm.accountStatus }}</a></li>
</ul>
</div>
</div>
</nav>
navbar.directive.js
(function() {
'use strict';
angular
.module('app')
.directive('mainNavbar', mainNavbar);
mainNavbar.$inject = ['userFactory'];
function mainNavbar(userFactory) {
var directive = {
restrict: 'E',
templateUrl: 'app/components/navbar/navbar.html',
scope: {
creationDate: '='
},
controller: NavbarController,
controllerAs: 'vm',
bindToController: true
};
return directive;
function NavbarController() {
var vm = this;
// solution 1 (doesn't work)
vm.accountStatus = userFactory.userStatus;
vm.accountStatusLink = userFactory.userStatusLink;
// solution 2 (doesn't work)
//vm.accountStatus = userFactory.getUserStatus();
//vm.accountStatusLink = userFactory.getUserStatusLink();
}
}
})();
user.factory.js
(function() {
'use strict'
angular
.module('app')
.factory('userFactory', userFactory);
userFactory.$inject = ['$http', '$cookies'];
function userFactory($http, $cookies) {
var userStatusLink = '#/user/';
var userStatus = 'Sign Up / Log In';
var service = {
verifyUser: verifyUser,
storeUser: storeUser,
userStatusLink: userStatusLink,
userStatus: userStatus
};
return service;
/* verifyUser() snip */
function storeUser(user) {
$cookies.putObject('user', user); // stores user obj in cookies
userStatusLink = '#/signout/';
userStatus = 'Sign Out';
}
/* solution 2 getters
function getUserStatus() {
return userStatus;
}
function getUserStatusLink() {
return userStatusLink;
}
*/
}
})();
更新:
userFactory.storeUser(user)在.success回调中异步发生:
$http.post('someurl').success(function(user) {
userFactory.storeUser(user);
});
1楼
首先,登录和注销的显示值应该在指令内。 那个小部件(指令)应该是拥有登录/注销的所有表示的东西。
这听起来像你真的想在指令之间进行通信。 这是人们常常被困住的常见问题。 您可以在工厂中公开用户值并让指令监视更改,但这样做很昂贵,因为它占用了有限数量的手表中的1个。
在指令之间传递数据的常见模式是使用事件。
您的工厂或其他指令可以$rootScope.$emit('user-signed-in', userData) 。
这会在$ rootScope和所有父作用域上发出一个事件,但是没有,所以它比$ broadcast更快。
然后你的指令监听事件$rootScope.on('user-signed-in', function(userData) {}) 。
2楼
您是否尝试过制作getUserStatusLink和getUserStatus方法,并将视图绑定到这些方法?
function userFactory($http, $cookies) {
...
var service = {
...
getUserStatusLink: function() {
return userStatusLink;
},
getUserStatus: function() {
return userStatus;
}
};
...
}
然后在你的NavBar控制器中:
function NavbarController() {
...
vm.accountStatusLink = userFactory.getUserStatusLink();
vm.accountStatus = userFactory.getUserStatus();
}
当您在userFactory中更新userStatusLink和userStatus时,这应该可以满足您的要求。
更新:
由于您的storeUser()方法是异步调用的,因此在设置新值时不会触发另一个摘要周期。
因此,您应该使用$ timeout服务强制Angular执行摘要周期:
userFactory.$inject = [ ..., '$timeout'];
function userFactory( ..., $timeout) {
...
function storeUser(user) {
...
// forces Angular to perform a digest cycle, thus refreshing your view
$timeout(function() {
userStatusLink = '#/signout/';
userStatus = 'Sign Out';
});
}
...
}
更新2:
使用jsFiddle这个实现。 我包含了两种方法,所以你可以看到使用$ timeout和不使用$ timeout的区别: :
我在一个地方引导你错了,更新控制器变量以直接访问方法,如下所示:
function NavbarController() {
...
// remove the parens at the end of userFactory.getUserStatusLink();
vm.accountStatusLink = userFactory.getUserStatusLink;
// remove the parens at the end of userFactory.getUserStatus();
vm.accountStatus = userFactory.getUserStatus;
}
然后更新您的视图以实际调用方法:
<!-- add parens to view to make it actually call the methods -->
<li><a ng-href="{{ vm.accountStatusLink() }}">{{ vm.accountStatus() }}</a></li>
最后更新:
结果是$ timeout是不必要的,因为Angular在$ http服务的成功回调中执行摘要循环。 只需更新视图即可直接访问该方法就足以解决问题。
3楼
您是否尝试复制链接并在布尔方法上使用ng-hide / ng-show来指示您的用户是否已登录?