AngularJS:侦听事件,一个接一个地

3
有没有一种Angular方式来监听一个接着一个发生的事件呢?例如,我想在$rootScope上监听$routeChangeSuccess和$viewContentLoaded事件。当第一个事件发生后,第二个事件发生时,我想调用一个回调函数。这是可能的吗?还是我必须自己编写代码?如果可以的话,配置事件顺序是否重要会很好。你有什么想法如何实现这样的行为吗?
更新:因为我在网上没有找到任何相关内容,所以我自己想出了解决方案。我认为它可以工作,但我不知道这种方法是否有任何缺点。请问如何将此全局变量集成到AngularJS项目中?或者甚至作为一个Bower组件?我应该将函数附加到作用域还是根作用域?感谢您的帮助!以下是Plunker链接和代码:http://plnkr.co/edit/slfvUlFCh7fAlE4IPt8o?p=preview
var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.events = [];

  var successiveOn = function(events, eventScope, callback, orderImportant) {
    // array for the remove listener callback
    var removeListenerMethods = [];
    // events array that is passed to the callback method
    var eventsArr = [];
    // how many events are fired
    var eventCount = 0;
    // how many events should be fired
    var targetEventCount = events.length;
    // track the next event, only for orderImportant==true
    var nextEvent = events[0];
    // iterate over all event strings
    for (var i = 0; i < events.length; i++) {
      var event = events[i];
      // attach an $on listener, and store the remove listener function
      var removeListener = eventScope.$on(event, function(evt) {
        if (evt.name == nextEvent || !orderImportant) {
          ++eventCount;
          nextEvent = events[eventCount];
          eventsArr.push(evt);
          // if all events has fired, call the callback method and reset
          if (eventCount >= targetEventCount) {
            callback(eventsArr);
            nextEvent = events[0];
            eventCount = 0;
            eventsArr = [];
          }
        }
      });
      removeListenerMethods.push(removeListener);
    }

    // the return function is a anonymous function which calls all the removeListener methods
    return function() {
      for (var i = 0; i < removeListenerMethods.length; i++) {
        removeListenerMethods[i]();
      }
    }
  }

  // order is unimportant
  var removeListeners = successiveOn(["orderUnimportant1", "orderUnimportant2", "orderUnimportant3"], $scope, function(events) {
    var str = "Events in order of trigger: ";
    for (var i = 0; i < events.length; i++) {
      str += events[i].name + ", ";
    }
    $scope.events.push(str);
  }, false);

  $scope.$broadcast("orderUnimportant1");
  $scope.$broadcast("orderUnimportant2");
  $scope.$broadcast("orderUnimportant3"); // Events were triggered 1st time

  $scope.$broadcast("orderUnimportant3");
  $scope.$broadcast("orderUnimportant2");
  $scope.$broadcast("orderUnimportant1"); // Events were triggered 2nd time, order doesn't matter
  removeListeners();

  // order is important!
  var removeListeners = successiveOn(["OrderImportant1", "OrderImportant2", "OrderImportant3"], $scope, function(events) {
    var str = "Events in order of trigger: ";
    for (var i = 0; i < events.length; i++) {
      str += events[i].name + ", ";
    }
    $scope.events.push(str);
  }, true);

  $scope.$broadcast("OrderImportant1");
  $scope.$broadcast("OrderImportant2");
  $scope.$broadcast("OrderImportant3"); // Events were triggered

  $scope.$broadcast("OrderImportant1");
  $scope.$broadcast("OrderImportant3");
  $scope.$broadcast("OrderImportant2"); // Events were NOT triggered
  removeListeners();
});
2个回答

11

使用 $q 服务,也称为 promise。

var routeChange = $q.defer();
var contentLoaded = $q.defer();

$rootScope.$on("$routeChangeSuccess", function() {
  routeChange.resolve();
});

$rootScope.$on("$viewContentLoaded", function() {
  contentLoaded.resolve();
});

$q.all([contentLoaded.promise, routeChange.promise]).then(function() {
  //Fire your callback here
});

具体订单:

routeChange.then(function() {
  contentLoaded.then(function () {
     //Fire callback
  });
});

没有令人讨厌的回调函数套娃:

var routeChangeHandler = function() {
  return routeChange.promise;
}

var contentLoadedHandler = function() {
  return contentLoaded.promise
}

var callback = function() { 
  //Do cool stuff here
}

routeChangeHandler
  .then(contentLoadedHandler)
  .then(callback);

这相当性感...

关于链式Promise的更多信息


嘿,感谢您的答案。您的解决方案看起来更清晰,但缺乏检查事件是否按特定顺序分派的能力。有没有想过如何使用 $q.all 方法处理这个问题? - 23tux

3

如果你想使用纯AngularJS工具来处理,我认为Stens的回答是最好的方法。然而,通常这种情况表明您需要定期处理更复杂的事件问题。如果是这种情况,我建议您查看Reactive Extensionsrx.angular.js桥接库。

使用JavaScript的响应式扩展(RxJS),您可以将代码简化为以下内容:

Rx.Observable.combineLatest(
    $rootScope.$eventToObservable('$routeChangeSuccess'),
    $rootScope.$eventToObservable('$viewContentLoaded'),
    Rx.helpers.noop
)
.subscribe(function(){
    //do your stuff here
})

1
嗯,使用另一个库不是我想要的。但我不知道那个库,它看起来很酷,谢谢!;) - 23tux
是的,完全可以理解。但 Rx 真的很棒,所以我想在这里分享一下。如果你喜欢的话,请考虑点赞;-) - Christoph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接