To understand why the solution with formHolder
work you have to understand JavaScript prototypes chain first. Let’s illustrate the first case without formHolder
in the following pseudo code:
$parentScope = {
//I'm a parent scope inside Ctrl2
productForm:{} //to avoid undefined reference error
}
$childScope = {
//I'm a child scope created by by ng-include
__protototype__: $parentScope
}
When the form
directive is parsed it creates FormController
which is set on the $scope
property under key indicated in name
attribute value. This is pretty much equivalent to:
$childScope.productForm = $formCtrl;
After which the 2 scopes look like this:
$parentScope = {
//I'm a parent scope inside Ctrl2
productForm:{} //to avoid undefined reference error
}
$childScope = {
//I'm a child scope created by by ng-include
productForm: $formCtrl
__protototype__: $parentScope
}
So you actually ended up with 2 properties on different scopes holding different objects.
Now in the second case you have the following situation:
$parentScope = {
//I'm a parent scope inside Ctrl2
formHolder:{} //to avoid undefined reference error
}
$childScope = {
//I'm a child scope created by by ng-include
__protototype__: $parentScope
}
When the form
directive is setting FormController
instance on the $scope
this time it uses different property chain:
$childScope.formHolder.productForm = $formCtrl;
Which is equivalent to writing:
var formHolder = $childScope.formHolder; //since formHolder isn't defined on $childScope
//the JS runtime will look for it in the prototypes chain and find it inside $parentScope
//so here formHolder is the very same object you created and set on $parentScope
formHolder.productForm = $formCtrl;
Hope it helps to understand why the second option works. As for the second part of you question – your solution is simple and perfectly viable – but there are couple of other ways to handle it which is best depends on the actual usage context:
- using directive without child scope to extract common markup and parts of functionality
- using directive with child scope that would communicate state changes either via direct parent scope property access or via emitted events
- using a custom include directive that would not create child scope