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

tur*_*ner 5 javascript twitter-bootstrap angularjs angularjs-directive

我有一个带有navbar指令和基本注册/登录功能的应用程序.我想在用户登录后更改导航栏上的一些单词(从"注册/登录"到"退出"),但我无法找到最佳(甚至是一种)方式来执行此操作.我已经尝试将我想要更改的变量/绑定的值设置为在用户登录时更新的工厂,但这不起作用,并且指令不会使用其新值更新.

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

我试过的解决方案:

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

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

})();
Run Code Online (Sandbox Code Playgroud)

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

    */

  }

})();
Run Code Online (Sandbox Code Playgroud)

更新:

userFactory.storeUser(user).success回调中异步发生:

$http.post('someurl').success(function(user) {
    userFactory.storeUser(user);
});
Run Code Online (Sandbox Code Playgroud)

kan*_*lm3 1

您是否尝试过创建 getUserStatusLink 和 getUserStatus 方法,并将您的视图绑定到这些方法?

function userFactory($http, $cookies) {
  ...
  var service = {
    ...
    getUserStatusLink: function() {
      return userStatusLink;
    },
    getUserStatus:  function() {
      return userStatus;
    }
  };
  ...
}
Run Code Online (Sandbox Code Playgroud)

然后在您的导航栏控制器中:

function NavbarController() {
  ...
  vm.accountStatusLink = userFactory.getUserStatusLink();
  vm.accountStatus = userFactory.getUserStatus();
}
Run Code Online (Sandbox Code Playgroud)

当 userFactory 中更新 userStatusLink 和 userStatus 时,这应该执行您希望执行的操作。

更新:

由于您的storeUser()方法是异步调用的,因此当您设置新值时,它不会触发另一个摘要周期。因此,您应该强制 Angular 使用 $timeout 服务执行摘要循环:

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';
    });
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

更新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;
}
Run Code Online (Sandbox Code Playgroud)

然后更新您的视图以实际调用方法:

<!-- add parens to view to make it actually call the methods -->
<li><a ng-href="{{ vm.accountStatusLink() }}">{{ vm.accountStatus() }}</a></li>
Run Code Online (Sandbox Code Playgroud)

最终更新:

事实证明 $timeout 是不必要的,因为 Angular 在 $http 服务的成功回调中执行摘要循环。只需更新视图以直接访问该方法就足以修复它。