1. Cross-Widget Events with $rootScope
Every widget's controller shares the same page-level $rootScope,
which makes it a natural event bus: one widget broadcasts an
event downward (or emits it upward) through the scope tree, and
any other widget listening with $on receives it — no direct
reference between the two widgets required.
function($rootScope) {
var c = this;
c.selectedGroup = '';
c.applyFilter = function() {
$rootScope.$broadcast('incident-filter-changed', {
group: c.selectedGroup
});
};
}
function($rootScope, $scope) {
var c = this;
$scope.$on('incident-filter-changed', function(event, payload) {
c.data.action = 'filter';
c.data.group = payload.group;
c.server.update();
});
}
This is deliberately similar to an Angular EventEmitter paired
with a shared service's Subject — the mechanics differ, but the
shape of the problem it solves (decoupled sibling components reacting to each
other) is the same one you've solved before.
3. Choosing Events vs. Shared State
A rough rule that holds up well in practice: reach for events when you're modeling something that happened at a point in time (a filter was applied, a record was saved) that other widgets should react to once. Reach for a shared service when you're modeling state that needs to be read by multiple widgets, including ones that mount after the state was last set — an event fired before a widget existed is simply missed, while a shared service's current value is always readable on demand.
4. Hands-on Exercise
Build a two-widget filter/list pair
Requirements:
- Build the filter widget and list widget shown above, place both on the same portal page, and confirm selecting a group in the filter widget updates the list widget via the broadcast event.
- Now add a shared service holding the currently selected group, updated whenever the filter changes.
- Add a third widget — a small "Currently Filtering By" label — that reads the shared service's value on load (not via an event) so it shows the correct group even if it's added to the page after a filter selection was already made.
- Explain, in a code comment, why the third widget uses the shared service instead of listening for the broadcast event.
5. Knowledge Check
Four quick questions. Expand each to check your answer.
Q1
How can two widgets in different containers on the same page communicate without a direct reference to each other?
How can two widgets in different containers on the same page communicate without a direct reference to each other?
Every widget controller shares the same page-level $rootScope. One widget broadcasts or emits an event through it with $rootScope.$broadcast()/$emit(), and any other widget listening with $scope.$on() for that event name receives it, with no direct reference between the two widgets needed.
Q2
What plays the role of an Angular EventEmitter/shared service pairing in the Service Portal widget world?
What plays the role of an Angular EventEmitter/shared service pairing in the Service Portal widget world?
$rootScope.$broadcast()/$emit()/$on() for one-off event notifications, and an injectable AngularJS service (registered as an Angular Provider record) for shared, persistent state — the same two tools, conceptually, that solve decoupled cross-component communication in modern Angular, just via different specific APIs.
Q3
Why might a widget miss a broadcast event that another widget already fired?
Why might a widget miss a broadcast event that another widget already fired?
Events are only received by widgets that are already listening at the moment the event fires. A widget that mounts after the event was broadcast — for example, one added to the page later, or one whose container renders after the event fired — simply never sees it, since there's no replay or buffering of past events.
Q4
When should you reach for a shared service instead of a broadcast event?
When should you reach for a shared service instead of a broadcast event?
When you're modeling persistent state that multiple widgets need to read on demand, including widgets that might mount after the state was last changed — a shared service's current value is always readable, unlike an event which is only received by listeners active at the moment it fires.