【问题标题】:Route change events while trying to avoid using $rootScope尝试避免使用 $rootScope 时路由更改事件
【发布时间】:2017-01-25 18:44:12
【问题描述】:

正如Angular team(和多个blogs)所建议的那样,我尽量避免在我的应用中使用$rootScope

$rootScope存在,但可以用来作恶

“当然,全局状态很糟糕,你应该谨慎使用$rootScope, 就像您(希望)在任何语言中使用全局变量一样。 特别是,不要将其用于代码,仅用于数据。如果你想 在$rootScope 上放一个函数,几乎总是把它放在一个 可以在需要的地方注入服务,并且更容易 经过测试。” - 来自Angular FAQ

但在我的一个应用程序中,我使用了多次事件,例如$routeChangeStart,它们是广播事件,使用$rootScope

/* Force redirection to home page when a connected user calls login page */
$rootScope.$on("$routeChangeStart", function(event, next, current) {
    if(next.$$route.originalPath == '/login' && Session.isUserConnected()) {
        $location.path("/home");
    }
}

在这些情况下,我没有办法避免$rootScope

  • 有没有更优雅的方法来做这种技巧?
  • 这是我的应用程序使用它的设计错误吗?
  • 我必须在绝对必要时辞职才能使用它吗?

如果您希望我提供更多代码示例,请告诉我。

【问题讨论】:

  • 你读过这个global state sucks and you should use $rootScope sparingly???
  • @RameshRajendran 是的,来自我提供的first link(最后一段)。它来自 Angular 文档常见问题解答
  • 对于这种情况,您只是在收听广播到 $rootScope 的事件,我认为这是一个有效的用例。

标签: angularjs angularjs-routing angularjs-rootscope


【解决方案1】:

如果您不想在这种情况下使用$rootScope您可以使用强大的resolve 来实现此目的

由于我看到您正在使用ngRoute 模块,因此我为ngRoute 解析创建了Plunker 和代码。如果您也需要,我可以为ui-router 创建一个。

使用 Resolve 使代码执行得更快,因为它不会经历 DigestCycle

您可以通过注入会话从Session.isUserConnected() 获取用户标志。

然后您可以使用该变量来重定向路由。

// Code goes here

angular.module('Test', ['ngRoute'])
.config(function($routeProvider) {
     var user = true;
     //var user = Session.isUserConnected(); You can use your logic here
    $routeProvider
   .when("/login", {
        template: "Login View",
        resolve: {
           
         data: function($q, $timeout,$location) {
             var deferred = $q.defer();
            $timeout(function() {
              
              if (user) {
                $location.path("/home");
                deferred.reject();
              } else {
                deferred.resolve();
              }
            });
    
            return deferred.promise;
            }
        }
    })
     .when("/home", {
        template: "Home View. It is redirected from Login by checking the user condition. Without using the rootscope",
      })
    .otherwise({redirectTo:'/login'});
})

 
  
<!DOCTYPE html>
<html ng-app="Test">
  <head>
    <link rel="stylesheet" href="style.css" />
  </head>
 
  <body>
    <div ng-view></div>
    
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
    <script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-route.js"></script> 
  </body>
</html>

主要部分在这里:

data: function($q, $timeout, $location) {
    var deferred = $q.defer();
    $timeout(function() { 
        if (user) {
            $location.path("/home");
            deferred.reject();
        } else {
            deferred.resolve();
        }
    });
    return deferred.promise;
}

HERE IS A WORKING DEMO

【讨论】:

  • 有趣的观点。在性能和设计方面,是不是比使用$rootScope 更好?你认为我应该使用它,还是只是“如何做不同”的建议?
  • 由于$rootScope 的更改将再次运行摘要循环并且解析仅在调用路由时运行一次,因此与$routeScope 相比,解析可能更好,而且,正如你所问的是$rootScope 的替代品。
  • 它没有回答,因为我认为它仍然更复杂,并且不确定性能是否更好。无论如何,我赞成你展示另一种方式来做这种事情的努力。 :-)
  • Np,等待更多答案,我也会寻找其他方法。 :-)
【解决方案2】:

你看错了。 首先,这个事件是由 Angular 团队添加的——你认为他们建议不要使用它吗?:D 那篇文章是关于你不应该把所有东西都放在 $rootScope 中,这对于初学者来说似乎是一种简单的方法。

实际上,使用$rootScope - 用于全局事件是绝对可以的 - 这就是这项服务的实际目的。

【讨论】:

  • 我想知道是否有关于如何构建这段代码的“良好实践”(就像它在 $rootScope 中一样,你可以在任何地方编写它),以使其尽可能清晰易读跨度>
  • “全局的东西总是正确的”,应该在 app.run() 中。 --(因为它总是在你的应用初始化时执行)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
  • 2016-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多