Software development and beyond

How to communicate with Angular components outside of Angular

Recently I had to figure out the way to interact with Angular components from outside of Angular, from plain JavaScript rendered to a page. In my case I was opening a modal dialog written in Angular from a traditional server-side rendered page.

I imagine I am not the only one who needs to mix Angular code with other code on the page so I want to share a piece of code that will allow you to do that easily. I based it on a publish-subscribe pattern to separate the code in a nice and clean way.

The basic use-cases are.:

I wrote it as Angular service, named GlobalPubSub. This service has to be part of the Angular module that you load in the page. It will then attach functions on the global window object that you can call outside of Angular.

Basic usage:

A few notes on implementation:

Here it is, let me know what you think!

import {Injectable, NgZone} from "@angular/core";

/**
* Service that allows Angular components to receive and fire
* events from outside
*
* Usage from outside of Angular:
* window.fireAngularEvent('sampleEventName', args)
* window.subscribeToAngularEvent('sampleEventName', fn)
*
* Usage from Angular component:
* globalPubSub.fireEvent('sampleEventName', args)
* globalPubSub.subscribe('sampleEventName', fn)
*/

@Injectable()
export class GlobalPubSub {

allowedEvents = [
"sampleEventName",
"sampleEventName2"
];

private subscriptions : {[key:string]:Function[];} = {};

constructor(private zone: NgZone) {
this.allowedEvents.forEach((eventName) => {
this.subscriptions[eventName] = []
});

window['fireAngularEvent'] = (eventName, args) => {
if (!this.subscriptions[eventName]) {
throw new Error('Event has to be defined in the event list.')
}

zone.run(() => {
this.fireEvent(eventName, args);
});
};

window['subscribeToAngularEvent'] = (eventName, fn) => {
this.subscribe(eventName, fn);
};
}

subscribe(eventName: string, fn: Function) {
if (!this.subscriptions[eventName]) {
throw new Error('Event has to be defined in the event list.');
}

this.subscriptions[eventName].push(fn);
}

fireEvent(eventName: string, args) {
if (!this.subscriptions[eventName]) {
throw new Error('Event has to be defined in the event list.');
}

this.subscriptions[eventName].forEach((fn) => {
fn.apply(null, args);
});
}
}

Last updated on 22.1.2018.

angular javascript popular