Reputation: 239814
Say I have an angular SPA running inside a browser (window 1). And say that there's some activity that leads to us launching a separate angular application inside of a new window (opened by $window.open()
) (window 2).
Windows 1 & 2 want to stay somewhat connected. They're running different applications but they're both dealing with the same subject matter. When one changes state, the other might need to react to that. And vice versa.
I'm looking for some good way for these two apps, in two separate browser windows, to send events back and forth.
Now, for fun, there might be another window (window 3) running the same application as window 1. This separate instance should not be interfered with in any way by windows 1 & 2. And, of course, window 3 could launch it's own equivalent of window 2 (window 4).
So windows 1 & 2 (running different apps) should be able to message back and forth. And windows 3 & 4 similarly. But 1 shouldn't affect 3 & 4, and so on.
The obvious relationship between them is that window 1 called $window.open()
and window 2 can access $window.opener
- so they can both access window
objects - but how do I "angular-ise" up this situation?
The current implementation is using $localStorage
and watching for storage events to link windows 1 & 2,but of course this completely fails the non-interference requirement once windows 3 & 4 show up.
Upvotes: 1
Views: 2987
Reputation: 4935
If you are lucky enough to have all of your window on the same domain then you can use postMessage as already mentioned or even better HTML5 localStorage. You have an article and demo available here. Mainly what's going on here :
All window listen to storage event with something like :
window.addEventListener("storage", handle_storage, false);
For every window you can have a different handle_storage
function or a common one that checks which url is responsible for the storage event.
Advantages :
Disadvantages :
Hope this will help.
Upvotes: 2
Reputation: 18888
This sounds like a good case for using application events.
You'll want one object to have a publish/subscribe interface:
var dispatcher = {
subscriptions: {},
publish: function(eventName, publisher, data) {
// loop through subscribers and notify them, passing publisher and data
// var subscriber = this.subscribers[eventName][i];
// subscriber.callback.call(subscriber.context, publisher, data);
},
subscribe: function(eventName, context, callback) {
this.subscriptions[eventName] = this.subscriptions[eventName] || [];
this.subscriptions[eventName].push({
context: context,
callback: callback
});
}
};
When you open a new window, set this object reference as a property on the new window.
var win = window.open(...);
win.dispatcher = dispatcher;
Now each window, including the "top" window should have a global variable called dispatcher
that you can use to subscribe to and publish events:
(from main window)
dispatcher.subcribe("item.added", this, function(publisher, data) {
// "publisher" is the object publishing the event
// "data" is arbitrary data passed along in the event
});
(from a sub window)
dispatcher.publish("item.added", this, {
name: "Foo"
});
I haven't used AngularJS much yet, so I'm not sure if it comes with some sort of event framework outside of DOM events. There are a bunch of implementations of the pub/sub model in JavaScript, and you could probably throw a dart at a Google search and land on one. I created a simple JavaScript class library that might fit the bill. It has no external dependencies: https://github.com/gburghardt/events
Advantages
Disadvantages
Upvotes: 2