Parent/Child Controller Communication
AngularJS - Communicating Between Controllers - Part 1
I've been teaching AngularJS to a couple of friends lately and they almost universally ask the same question:
How do I pass information (state) between controllers?
It's a great question and it's often not obvious to new Angular users. The answer is a lot more complex than one might think (but the implementation is simple).
There are a number of ways to communicate between controllers. Over the next series of posts, I'm going to demonstrate those ways and discuss some of the pitfalls of each mechanism.
In this talk, I'm going to discuss the easiest, but most likely to be abused approach:
Parent-Child Controller Communication
As the name suggests, this mechanism only works between two controllers where one controller (child) is nested inside another controller (parent).
<div ng-controller="ParentCtrl">
<div ng-controller="ChildCtrl"></div>
</div>
Scopes
, which represent the context (data available to the view) of the controller in AngularJS, are hierarchal. This means that variables and functions defined on the parent controller are available to child. This has a couple of implications:
Variables defined on the parent's scope are copied to the child's scope.
Looking at the following View:
<div ng-controller="ParentCtrl">
<h1>{{ title }}</h1>
<div ng-controller="ChildCtrl">
<h1>{{ title }}</h1>
</div>
</div>
If the controllers are defined as such:
app.controller("ParentCtrl", [ '$scope', function($scope){
$scope.title = "I'm the Parent.";
}]);
app.controller("ChildCtrl", [ '$scope', function($scope){
// Nothing defined on $scope
}]);
You will have something that looks like this:
If a child defines a variable with the same name as a variable on the parent's scope, the child is effectively shadowing (hiding) the parent-scope variable.
In the previous example, the $scope.title
variable is being inherited by the child scope from the parent's. If the child defines its own value for $scope.title
:
app.controller("ParentCtrl", [ '$scope', function($scope){
$scope.title = "I'm the Parent.";
}]);
app.controller("ChildCtrl", [ '$scope', function($scope){
$scope.title = "I'm the Child.";
}]);
It will hide the parent's value for $scope.title
, but only within the child's context (the parent's is left alone):
Children can directly access the parent-scope (even modify it), but the parent cannot access it's children's scopes.
Angular scopes include a variable called $parent
(i.e. $scope.$parent
) that refer to the parent scope of a controller. If a controller is at the root of the application, the parent would be the root scope ($rootScope
).
Child controllers can therefore modify the parent scope since they access to it. This is one way for the child to inform the parent that something has happened.
Modifying our example a little bit:
<div ng-controller="ParentCtrl">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<div ng-controller="ChildCtrl">
<h1>{{ title }}</h1>
<input type="text" ng-model="$parent.description" />
</div>
</div>
We can reference the parent's variable from a textbox bound by ng-model
with the child controller. Any update made in the textbox will propagate to the parent:
There's no accompanying JavaScript code (hence the power of Angular!).
Benefits and Pitfalls of Parent-Child Scope Communication
In general, I do not recommend this technique for communicating between two controllers because it promotes tight coupling between the Parent and the Child. However, the technique is easily implemented if you're willing to incur technical debt as a consequence of using this strategy.
Pitfalls
- Child is too aware of the parent's model.
- Children are capable of incorrectly mutating parent's state; like overwriting a variable on the parent.
- Children are rarely reusable because they impose requirements on the parent controller.
Benefits
- Fastest, least complex way to communicate between nested controllers.
- Good when the child is logically coupled to a parent (say a ZipCode controller within an Address controller).
Code
You can find all the examples from this blog post here: https://github.com/rclayton/NG-Communicate-Ctrls/tree/master/parent-child
Stumbling my way through the great wastelands of enterprise software development.