An Angular app employs a number of framework artefacts to achieve any functionality. Any Angular app has multiple views, controllers, services, filters, and also directives, all working together in unison. The need for communication between these constructs thus becomes imperative.
Scopes are a ubiquitous mechanism for communication and data sharing. Scopes are used so often that we do not put much thought into how and what we are actually sharing.
To reiterate how scopes work in Angular, look at this:
- Scopes are created as part of the directive execution, or as part of the application bootstrapping process when an application starts
- At any given time in the application, one or more scopes are active
- Scope hierarchy is driven by the HTML element hierarchy
- A child scope inherits from its parent scope (the prototypal inheritance) and hence can access all properties of the parent scope (isolated scope is an exception).
Given how scopes work, parent/child views can implicitly communicate with each other using the associated parent scope.
Scopes as a data sharing mechanism have their limitation too.
The very fact that scopes share data with a child scope through inheritance implies two unrelated scopes or sibling scopes cannot share data/communicate directly. In such a scenario, we need one of the following:
- Use the parent scope as a communication channel. This parent can be an immediate parent in the case of sibling scopes or a parent scope up higher in the hierarchy.
- Or as a special case, we can use
$rootScopeto communicate and share data. Since
$rootScopeis the root for the complete application scope hierarchy, any data set on
$rootScopecan be accessed throughout all scopes.
- Use services to communicate between such scopes. This is possible because services by nature are singleton.
While all these methods try to solve the same problem, there are some that are preferable to others.
$rootScope should be avoided as this results in the creation of a global state, which is never a good thing.
Prefer services over parent scopes when it comes to sharing data. The disadvantage of the parent scope is that, just by looking at variables defined on the parent scope, one cannot determine who is consuming them, whereas services makes this dependency explicit.
This also happens when we break a large view into multiple smaller manageable views. We may be taking dependency implicitly on the scope that these new views inherit. In such a case, too, we should try to evaluate whether a service can be used.