无法在AngularJS控制器中捕获事件

时间:2014-05-27 08:54:55

标签: angularjs angularjs-scope angular-http-interceptors

我正在尝试实施用户身份验证系统。我读过401 http状态代码和HTTP Auth Interceptor Module

我已经用bower下载了该模块并将其加载到我的app模块中。我还没有使用它,但是当用户在浏览器中打开应用程序时,我想使用此模块触发的相同事件来显示用户登录弹出窗口。

我的所有控制器都是CoreController的孩子。 CoreController解析当前用户。当应用程序加载时没有用户登录,因此我想显示发出事件的登录表单:event:auth-loginRequired(与http-auth-interceptor相同)。

在此CoreController中,我有另一条规则正在侦听此特定事件(event:auth-loginRequired)。如果检测到此事件,控制器将显示弹出窗口,调用其state id。

我遇到的问题是控制台说我已经正确地发出了事件,但我的监听器没有被触发,因此登录弹出窗口没有显示。

这是我的CoreController

/**
 * Index controller definition
 *
 * @scope Controllers
 */
define(['./../module', 'moment'], function (controllers, moment) {
    'use strict';

    controllers.controller('CoreController', ['$scope', '$rootScope', '$state', 'user', function ($scope, $rootScope, $state, user)
    {
        console.log('Core Controller Loaded');
        $scope.loader = true;

        $scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams)
        {
            $scope.loader = true;
        });

        $scope.$on('event:auth-loginRequired', function(event, toState, toParams, fromState, fromParams)
        {
            console.log('catch auth required');
            $state.go("main.login");
        });

        if (user.isLogged == false) {
            console.log('emit auth required');
            $rootScope.$emit('event:auth-loginRequired');
        }
    }]);
});

我做错了什么?

干杯, 马克西姆

1 个答案:

答案 0 :(得分:8)

问题是您在$rootScope上发光,该事件无法到达您当地的$scope听众。

轻松出路不推荐):

    if (user.isLogged == false) {
        console.log('broadcast auth required');
        $rootScope.$broadcast('event:auth-loginRequired');
    }

此解决方案的问题在于,事件会从您的$rootScope向下冒泡到您的所有子范围。从性能的角度来看,这并不好。


更好的出路推荐):

    $rootScope.$on('event:auth-loginRequired', function(event, toState, toParams, fromState, fromParams)
    {
        console.log('catch auth required');
        $state.go("main.login");
    });

    if (user.isLogged == false) {
        console.log('emit auth required');
        $rootScope.$emit('event:auth-loginRequired');
    }

我们在$rootScope设置事件监听器,而$emitting$rootScope - 事件不会遍历您的$ scope层次结构并导致性能问题。


另一种方式,这是我从控制器处理$ rootScope事件监听器的首选方法,是在销毁本地$ scope时取消订阅事件监听器。

更好的出路强烈推荐(在我看来*)):

var mainModule = angular.module('myModule'); // this would be your core module, tying everything together. 

mainModule.config(function ($provide) {
  // Define an alternative to $rootScope.$on. 
  // $scope.subscribe will emulate the same behaviour, with the difference
  // of removing the event listener when $scope.$destroy is called. 

  $provide.decorator('$rootScope', function ($delegate) {
    Object.defineProperty($delegate.constructor.prototype, 'subscribe', {
      value: function (name, listener) {
        var unsub = $delegate.$on(name, listener);
        this.$on('$destroy', unsub);
      },
      enumerable: false
    });

    return $delegate;
  });
});

// Then in your CoreController

 $scope.subscribe('event:auth-loginRequired', function(event, toState, toParams, fromState, fromParams)
  {
      console.log('catch auth required');
      $state.go("main.login");
  });

  if (user.isLogged == false) {
      console.log('emit auth required');
      $rootScope.$emit('event:auth-loginRequired');
  }

这也是如此,您不再需要将$rootScope注入控制器以设置$rootScope侦听器(但这不适用于设置发射器)。

无论你决定解决这个问题,我都强烈建议你研究解决方案#2或#3。 #1绝对不是我推荐的东西。

祝你好运!