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

Javascript 用户登录后如何动态更新指令?,javascript,angularjs,twitter-bootstrap,angularjs-directive,Javascript,Angularjs,Twitter Bootstrap,Angularjs Directive,我有一个带有导航条指令和基本注册/登录功能的应用程序。我想在用户登录后更改导航栏上的一些单词(从“注册/登录”改为“注销”),但我想不出最好的(甚至是一种)方法。我尝试将要更改的变量/绑定的值设置为在用户登录时更新的工厂,但这不起作用,指令也不会用其新值更新 我的代码附在下面,具体的解决方案是赞赏的,但不是真的必要的,如果有人可以告诉我正确的方向,如何做到这一点,这将是非常有帮助的 我尝试过的解决方案: 工厂 将绑定变量设置为已更新的工厂变量 将绑定变量设置为这些变量的getter语句的输出

我有一个带有导航条指令和基本注册/登录功能的应用程序。我想在用户登录后更改导航栏上的一些单词(从“注册/登录”改为“注销”),但我想不出最好的(甚至是一种)方法。我尝试将要更改的变量/绑定的值设置为在用户登录时更新的工厂,但这不起作用,指令也不会用其新值更新

我的代码附在下面,具体的解决方案是赞赏的,但不是真的必要的,如果有人可以告诉我正确的方向,如何做到这一点,这将是非常有帮助的

我尝试过的解决方案:

  • 工厂
  • 将绑定变量设置为已更新的工厂变量
  • 将绑定变量设置为这些变量的getter语句的输出
  • Cookies(除非有人说服我这是解决问题的好方法,否则我宁愿避免使用Cookies)
  • 将绑定变量设置为Cookie中的值
不幸的是,这些都不会导致指令变量动态更新。我觉得解决办法很简单,但我想不出我应该做什么

可能的解决办法:

  • 使用路由,例如在用户登录时将视图从一个导航栏更改为另一个导航栏,尽管这看起来很笨拙
  • $rootScope(不完全确定如何使用它,我猜这是错误的用法)
navbar.html

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)
回调中异步发生。成功
回调:

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

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

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

这听起来好像你真的在试图在指令之间交流。这对于人们来说是一件很常见的事情。您可以在工厂中公开用户值,并使用指令watch进行更改,但这很昂贵,因为它使用了有限数量的手表中的1个

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

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


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

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

function userFactory($http, $cookies) {
  ...
  var service = {
    ...
    getUserStatusLink: function() {
      return userStatusLink;
    },
    getUserStatus:  function() {
      return userStatus;
    }
  };
  ...
}
然后在导航栏控制器中:

function NavbarController() {
  ...
  vm.accountStatusLink = userFactory.getUserStatusLink();
  vm.accountStatus = userFactory.getUserStatus();
}
当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';
    });
  }
  ...
}
更新2:

使用此实现使用JSFIDLE。我提供了两种方法,您可以看到使用$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服务的成功回调中执行摘要循环。只需更新视图以直接访问该方法就足以修复它。

    我没有,但我如何获得该布尔值?我不知道如何更改指令必须使用的值。您可以尝试使用ng show和ng hide-这将是一个很好的解决方案,但我没有办法将“登录”布尔值添加到指令中,由于处理登录的逻辑在不同的控制器中。这似乎是一个复杂/复杂的解决方案,这真的是最好的方法吗?我觉得应该有一种更简单的方式来传递信息。我不想在指令之间进行通信,而只是在工厂和指令之间进行通信。如果不使用事件,唯一可以做的事情就是在工厂上公开
    getUser
    方法,并在指令中对该函数执行
    $watch
    ,如果用户返回,则他们将登录。这意味着您将检查每个角度生命周期中是否存在用户,这是非常频繁的。为什么是复杂的解决方案?非常简单。您尝试过吗?这实际上是我在解决方案2中尝试过的,它的结果似乎与直接将导航栏的变量设置为工厂的变量(正如我现在所做的那样)相同。是否异步调用storeUser?也许您应该尝试在$timeout方法中包装设置userStatusLink和userStatus的位置,以便在设置这些变量后强制Angular运行摘要循环。示例:$timeout(函数(){userStatusLink='blah';userStatus='blah';});所以在.success回调中调用storeUser(),这会被认为是异步调用的吗?(抱歉,这是promises的新功能)是的,这意味着它被异步调用,这意味着它超出了Angular的摘要周期。因此,为了在设置新值后强制Angular执行另一个摘要循环,只需在
    $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>