简体   繁体   English

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

[英]How to dynamically update directive once user is logged in?

I have an app with a navbar directive and basic sign up/log in functionality. 我有一个带有navbar指令和基本注册/登录功能的应用程序。 I want to change some of the words on the nav bar (from 'signup/login' to 'sign out') once the user is logged in, but I can't figure out the best (or even one) way to do this. 我想在用户登录后更改导航栏上的一些单词(从“注册/登录”到“退出”),但我无法找到最佳(甚至是一种)方式来执行此操作。 I've tried setting the value of the variable/binding I want to change to a factory that gets updated when the user logs in, but this doesn't work, and the directive doesn't update with its new value. 我已经尝试将我想要更改的变量/绑定的值设置为在用户登录时更新的工厂,但这不起作用,并且指令不会使用其新值更新。

My code is attached below, specific solutions are appreciated but not really necessary, if anyone can just point me in the right direction with how to do this that would be very helpful. 我的代码附在下面,特定的解决方案是值得赞赏的,但并不是真的有必要,如果有人能指出我正确的方向,如何做到这将是非常有帮助的。

Solutions I've tried: 我试过的解决方案:

  • Factories 工厂
    1. setting binding variables equal to factory variables that are updated 设置绑定变量等于更新的工厂变量
    2. setting binding variables equal to the output of getter statements for those variables 设置绑定变量等于这些变量的getter语句的输出
  • Cookies (would prefer to avoid unless someone convinces me it's a good way of solving this) 饼干(宁愿避免,除非有人说服我这是解决这个问题的好方法)
    1. setting binding variables equal to values in cookies 设置绑定变量等于cookie中的值

Unfortunately none of these cause the directive variable to dynamically update as well. 不幸的是,这些都不会导致指令变量动态更新。 I feel like the solution is very simple but I can't think of what I should be doing. 我觉得解决方案很简单,但我想不出我应该做什么。

Potential Solutions: 潜在解决方案

  • using routing, eg changing the view from one navbar to another when the user is logged in, although this seems really clunky 使用路由,例如在用户登录时将视图从一个导航栏更改为另一个导航栏,尽管这看起来非常笨重
  • $rootScope (not entirely sure how to use this and I'm guessing it's the wrong use for this anyway) $ rootScope(不完全确定如何使用它,我猜这是错误的用途)

navbar.html 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 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 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;
    }

    */

  }

})();

Update: 更新:

userFactory.storeUser(user) is happening asynchronously inside of a .success callback: userFactory.storeUser(user).success回调中异步发生:

$http.post('someurl').success(function(user) {
    userFactory.storeUser(user);
});

First off the display values of login and logout should be within the directive. 首先,登录和注销的显示值应该在指令内。 That widget (directive) should be what owns all of the presentation of the login / logout. 那个小部件(指令)应该是拥有登录/注销的所有表示的东西。

This sounds like you are really trying to communicate between directives. 这听起来像你真的想在指令之间进行通信。 Which is a common thing for people to get stuck on. 这是人们常常被困住的常见问题。 You could expose the user values in the factory and have the directive watch for changes but that is expensive as it uses up 1 of the finite number of watches. 您可以在工厂中公开用户值并让指令监视更改,但这样做很昂贵,因为它占用了有限数量的手表中的1个。

The common pattern to communicate data between directives is to use events. 在指令之间传递数据的常见模式是使用事件。 Your factory or another directive could $rootScope.$emit('user-signed-in', userData) . 您的工厂或其他指令可以$rootScope.$emit('user-signed-in', userData)

This emits an event on the $rootScope and all parent scopes, but there are none so it quicker then a $broadcast. 这会在$ rootScope和所有父作用域上发出一个事件,但是没有,所以它比$ broadcast更快。

Your directive then listens for the event $rootScope.on('user-signed-in', function(userData) {}) . 然后你的指令监听事件$rootScope.on('user-signed-in', function(userData) {})

Have you tried making a getUserStatusLink and a getUserStatus method, and binding your view to those methods instead? 您是否尝试过制作getUserStatusLink和getUserStatus方法,并将视图绑定到这些方法?

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

And then in your NavBar controller: 然后在你的NavBar控制器中:

function NavbarController() {
  ...
  vm.accountStatusLink = userFactory.getUserStatusLink();
  vm.accountStatus = userFactory.getUserStatus();
}

This should do what you are looking for it to do when userStatusLink and userStatus are updated in your userFactory. 当您在userFactory中更新userStatusLink和userStatus时,这应该可以满足您的要求。

Update: 更新:

Since your storeUser() method is being called asynchronously, it is not triggering another digest cycle to happen when your new values are set. 由于您的storeUser()方法是异步调用的,因此在设置新值时不会触发另一个摘要周期。 So you should force Angular to perform a digest cycle using the $timeout service: 因此,您应该使用$ 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';
    });
  }
  ...
}

Update 2: 更新2:

Working jsFiddle with this implementation. 使用jsFiddle这个实现。 I included two methods so you can see the difference in using $timeout and not using $timeout: http://jsfiddle.net/HB7LU/15366/ 我包含了两种方法,所以你可以看到使用$ timeout和不使用$ timeout的区别: http//jsfiddle.net/HB7LU/15366/

I steered you wrong in one place, update your controller variables to access the method directly like so: 我在一个地方引导你错了,更新控制器变量以直接访问方法,如下所示:

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

And then update your view to actually call the methods: 然后更新您的视图以实际调用方法:

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

Final Update: 最后更新:

Turns out $timeout was unnecessary, since Angular performs a digest cycle in the success callback of the $http service. 结果是$ timeout是不必要的,因为Angular在$ http服务的成功回调中执行摘要循环。 Simply updating the view to access the method directly was enough to fix it. 只需更新视图即可直接访问该方法就足以解决问题。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM