用户登录后如何动态更新指令?

时间:2015-07-16 21:08:50

标签: javascript angularjs twitter-bootstrap angularjs-directive

我有一个带有navbar指令和基本注册/登录功能的应用。我希望在用户登录后更改导航栏上的一些字词(从#39;注册/登录'到#39;退出')但我无法确定用最好的(甚至是一种)方法做到这一点。我已经尝试将我想要更改的变量/绑定的值设置为在用户登录时更新的工厂,但这不起作用,并且指令不会更新新价值。

我的代码附在下面,特定的解决方案是值得赞赏的,但并非真的有必要,如果有人能指出我正确的方向,如何做到这一点将非常有帮助。

我尝试过的解决方案:

  • 工厂
    1. 设置绑定变量等于更新的工厂变量
    2. 设置绑定变量等于这些变量的getter语句的输出
  • Cookies(除非有人说服我这是一个解决这个问题的好方法,否则我宁愿避免)
    1. 设置绑定变量等于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);
});

3 个答案:

答案 0 :(得分:1)

首先,登录和注销的显示值应该在指令范围内。该小部件(指令)应该是拥有登录/注销的所有表示的内容。

这听起来像你真的想在指令之间进行通信。这是人们常常被困住的常见问题。您可以在工厂中公开用户值并让指令监视更改,但这样做很昂贵,因为它占用了有限数量的手表中的一个。

指令之间传递数据的常见模式是使用事件。您的工厂或其他指令可以$rootScope.$emit('user-signed-in', userData)

这会在$ rootScope和所有父作用域上发出一个事件,但没有,所以它比$ broadcast更快。

然后您的指令会侦听事件$rootScope.on('user-signed-in', function(userData) {})

答案 1 :(得分:1)

您是否尝试过制作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:http://jsfiddle.net/HB7LU/15366/

的区别

我在一个地方引导你错了,更新控制器变量以直接访问方法:

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服务的成功回调中执行摘要循环。只需更新视图即可直接访问该方法就足以解决问题。

答案 2 :(得分:0)

您是否尝试复制链接并在布尔方法上使用ng-hide / ng-show来指示您的用户是否已登录?