简体   繁体   English

AngularJS:一个接一个地听取事件

[英]AngularJS: Listen to events, one after the other

is there an angular-way to listen for events that occur one after the other? 是否有一种角度方式来监听一个接一个发生的事件? For example, I want to listen on a $rootScope for the $routeChangeSuccess and the $viewContentLoaded event. 例如,我想在$rootScope上监听$routeChangeSuccess$viewContentLoaded事件。 When the first event occurs, and after that, the second event occurs, I want to call a callback. 当第一个事件发生时,之后发生第二个事件,我想调用一个回调函数。

Is this possible? 这可能吗? Or do I have to write it on my own? 或者我必须自己写吗? It would also be nice to configure if the order of the events is important or not. 配置事件的顺序是否重要也是很好的。 Or any ideas, how to implement such a behaviour? 或者任何想法,如何实现这样的行为?

Update 更新

Because I haven't found anything on the web, I came up with my own solution. 因为我没有在网上找到任何东西,所以我提出了自己的解决方案。 I think it works, but I don't know if there are any drawbacks with this method. 我认为它有效,但我不知道这种方法是否有任何缺点。

And any suggestions how to integrate this global into an AngularJS project? 以及如何将此全局集成到AngularJS项目中的任何建议? Or even as a bower component? 或者甚至作为凉亭组件? Should I attach the function to a scope, or to the rootScope? 我应该将函数附加到作用域还是rootScope? Any help is appreciated! 任何帮助表示赞赏!

Here is the Plunker link and the code: http://plnkr.co/edit/slfvUlFCh7fAlE4IPt8o?p=preview 这是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();
});

Use the $q service aka the promise. 使用$q服务即承诺。

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
});

Specific Order: 具体订单:

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

Without the nasty callback soup: 没有令人讨厌的回调汤:

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

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

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

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

Thats pretty damn sexy... 那该死的性感......

More info on chained promises 关于链式承诺的更多信息

I think Stens answer is the best way to tackle this if you want to do it with pure AngularJS facilities. 我认为如果你想用纯粹的AngularJS设施来解决这个问题,Stens的答案就是解决这个问题的最佳方法。 However, often enough such cases indicate that you have to deal with more complex event stuf on a regular basis. 但是,这种情况经常表明你必须定期处理更复杂的事件。 If that's the case, I'd advice you to take a look at the Reactive Extensions and the rx.angular.js bridging library. 如果是这种情况,我建议你看一下Reactive Extensionsrx.angular.js桥接库。

With the Reactive Extensions for JavaScript (RxJS) you can simplify the code to this: 使用Reactive Extensions for JavaScript(RxJS),您可以将代码简化为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM