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

max*_*022 0 angularjs angularjs-scope angular-http-interceptors

我正在尝试实现用户身份验证系统.我读过有关401http状态代码和HTTP Auth拦截器模块的文章.

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

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

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

我的问题是,控制台是说,我已经正确地发出该事件,但我的听众不会被触发,因此登录弹出没有显示.

这是我的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');
        }
    }]);
});
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

干杯,马克西姆

Kas*_*wau 8

问题是你正在发光$rootScope,那个事件将无法到达你当地的$scope听众.

简单的出路(不推荐):

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

此解决方案的问题在于,事件将从您的$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');
    }
Run Code Online (Sandbox Code Playgroud)

在这里,我们正在设置事件监听器$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');
  }
Run Code Online (Sandbox Code Playgroud)

这也是,你不再需要注入$rootScope你的控制器来设置$rootScope监听器(这不适用于设置发射器).

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

祝好运!