Communicate between controllers in Angular by using a simple pubsub service in TypeScript.

 

I created a really simple angular PubSubService in TypeScript, to allow communication between controllers or directives or services.

 

In the example below, controller 1, fires an event and controller 2 reacts to the firing of the event.

 

 

module dev {
    "use strict";

    var appModule = angular.module("myApp", []);

    appModule.controller("MyController1", ["$scope", "pubSubService", ($scope, pubSubService)

    => new dev.MyController1($scope, pubSubService)]);

    appModule.controller("MyController2", ["$scope", "pubSubService", ($scope, pubSubService)
    => new dev.MyController2($scope, pubSubService)]);

    

 

    export class MyController1 {
        constructor(public $scope: ng.IScope, public pubSubService: PubSubService) {
            // Fire an an event
            pubSubService.publish("my-custom-event", "some publisher data");
            }
    }

    export class MyController2 {
        constructor(public $scope: ng.IScope, public pubSubService: PubSubService) {
            this.handleMyCustomEvent = this.handleMyCustomEvent.bind(this);

            // Subscribe to be notified, when "my-custom-event" is fired.
            pubSubService.subscribe("my-custom-event", this.handleMyCustomEvent);
        }
   
        handleMyCustomEvent(data: any) {
        // Do something, when an event is fired from MyController1.
        }
    }

 

    /**
     * This service can be used to share data between controllers by using a pub sub mechanism.
     */
    export class PubSubService {
        private nextListenerIndex: number;
        private listeners: Array<IListener>;

        constructor() {
            this.listeners = [];
            this.nextListenerIndex = 0; // The first subscription will be located at index 0;

            this.publish = this.publish.bind(this);
            this.subscribe = this.subscribe.bind(this);
            this.unsubscribe = this.unsubscribe.bind(this);
        }

        /**
         * Publish an event.
         * All subscribers will be notified.
         * @param name, is the name of the event and is case insensitive.
         */
        publish(name: string, data?: any) {
            for (var i = 0, length = this.listeners.length; i < length; i++) {
                const listener = this.listeners[i];
                if (listener && listener.name.toLowerCase() === name.toLowerCase()) {
                    listener.handler.call(null, data, listener.subData);
                }
            }
        }

        /**
         * Subscribe to be notified, when an event is published.
         * @param name, is the name of the event and is case insensitive.
         * @returns A token, that can be used to unsubscribe.
         */
        subscribe(name: string, handler: (data?: any, subData?: any) => void, data?: any): number {
            var token = this.nextListenerIndex;
           
            this.listeners[token] = {
                handler: handler,
                name: name,
                subData: data
            };
            this.nextListenerIndex += 1;

            return token;
        }

        /**
         * Remove the event listener subscription.
         * @param token received on subscribing to an event listener.
         */
        unsubscribe(token: number) {

            // This will create holes in the array, but for now we do not care.
            this.listeners[token] = null; 
        }
    }

    export interface IListener {
        // This function will be called when an event is published.
        // Data is the data from the publisher, subData is the data from the subscriber.
        handler: (data?: any, subData?: any) => void;
        name: string;
        subData?: any; // Data from the subscriber.
    }

    angular.service("pubSubService", () => new PubSubService());
}

Leave a Reply

Your email address will not be published. Required fields are marked *