2
\$\begingroup\$

Okay I have the following use case:

Module A broadcasts an event.
Module B listens to that event.
Maybe also Module C listens to that event.

Now Module B has to perform an asynchronous operation before Module A may proceed with its code.

I solved this by creating an custom module $deferredEvents which allows to queue up asynchronous tasks before proceeding.

Example: http://jsfiddle.net/68845rw4/

Module:

angular.module('deferredEvents', []).provider('$deferredEvent', function () {
 this.$get = function ($q) {
 /**
 * @param type String - 'broadcast' | 'emit'
 * @param $scope Scope
 * @param eventName String - name of the event
 */
 return function $deferredEvent(type, $scope, eventName) {
 var queueHelper = {
 queue: [],
 promise: $q.when(),
 /**
 * Promise will be executed after all previous promisses passed
 */
 appendThen: function appendThen () {
 return this.queuePromise(this.promise.then.apply(this.promise, arguments));
 },
 /**
 * Promise will be executed immediately
 */
 queuePromise: function queuePromise (promise) {
 if (promise === this.promise) {
 throw new Error('Can\'t wait for own promise');
 }
 // Execute promise
 promise = $q.when(promise);
 // Add the promise result to the queue
 this.promise = this.promise.then(function () {
 return promise;
 });
 return this.promise;
 }
 };
 var args = Array.prototype.slice.call(arguments, 3);
 var emitArgs = [eventName, queueHelper].concat(args);
 var event = $scope['$' + type].apply($scope, emitArgs);
 return queueHelper.promise.then(function() {
 return $q.all(queueHelper.queue);
 }).then(function (results) {
 var failed = results.some(function (val) {
 return val === false;
 });
 return failed ? $q.reject(event) : event;
 }, function () {
 return $q.reject(event);
 });
 };
 };
}).provider('$deferredEmit', function () {
 this.$get = function ($deferredEvent) {
 return function $deferredEmit($scope, eventName) {
 return $deferredEvent.apply(this, ['emit', $scope, eventName].concat(Array.prototype.slice.call(arguments, 2)));
 };
 };
}).provider('$deferredBroadcast', function () {
 this.$get = function ($deferredEvent) {
 return function $deferredBroadcast($scope, eventName) {
 return $deferredEvent.apply(this, ['broadcast', $scope, eventName].concat(Array.prototype.slice.call(arguments, 2)));
 };
 };
});
asked Jun 2, 2015 at 14:10
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Idea seems nice but for me it's quite hard to follow. Don't get me wrong, it might just be me!

But could you achieve the same functionality A proceeds when B has done it's thing just by passing a callback function in your broadcasted/emitted event?

angular.module('moduleA', ['moduleB'])
 .controller('OneCtrl', function($scope, $rootScope) {
 // broadcast event
 $scope.send = function() {
 console.log('broadcast event');
 $rootScope.$broadcast('event:my-event', callback);
 };
 // event callback
 var callback = function(result) {
 console.log('callback', result);
 };
 }); 
angular.module('moduleB',[])
 .controller('TheOtherCtrl', function($scope, $q, $timeout) {
 // receive event
 $scope.$on('event:my-event', function(event, callback) {
 console.log('received', event.name);
 // execute callback with process result
 process(true).then(callback, callback);
 });
 // some async processing
 function process(success) {
 return $timeout(function() {
 return success ? $q.when(true) : $q.reject(false);
 }, 800);
 }
 });

broadcast event
received event:my-event
callback true

answered Jun 2, 2015 at 20:17
\$\endgroup\$
6
  • \$\begingroup\$ Hey - thanks for the feedback - The reason why I chose the approach was that I don't know how many modules are listening on the event. \$\endgroup\$ Commented Jun 3, 2015 at 6:55
  • \$\begingroup\$ Ok, and there must a reason you need to wait for listeners to finish? \$\endgroup\$ Commented Jun 8, 2015 at 19:03
  • \$\begingroup\$ Yes - user interactions and ajax requests \$\endgroup\$ Commented Jun 8, 2015 at 19:12
  • \$\begingroup\$ This still bothers me. If I think e.g. conventional C# application and some class exposes event(s), then I can't think any case where I have cared about listeners and what it is those listeners are doing. \$\endgroup\$ Commented Jun 17, 2015 at 13:05
  • \$\begingroup\$ Well in Javascript has a lot of asynchronous code and you are able to decide in a listener function wether the event bubbles, executes the default behaviour and so on. \$\endgroup\$ Commented Jun 18, 2015 at 8:48

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.