I've a directive nested within another directive as in the below fiddle.
http://jsfiddle.net/sriramr/T7W6T/3/
My question is: if a variable in the parent directive changes value, how to automatically update the value of a variable in the child directive which is computed from the parent variable?
var myapp = angular.module('myApp',[]);
myapp.directive('parentDir', parentDir);
function parentDir() {
return {
restrict:'E',
controller: function eCtrl($scope) {
$scope.parVal = 100;
$scope.$on("event",function(e,data) {
console.log("emit")
$scope.parVal = 200;
})
},
template:'<div><first-dir></first-dir</div>'
}
}
myapp.directive('firstDir', firstDir);
function firstDir() {
return {
restrict:'E',
controller: function($scope) {
//$scope.$watch('parVal',function() {
$scope.childVal = $scope.parVal + 1;
//})
$scope.changeVal = function() {
$scope.$emit("event")
}
},
template:'<div>first Dir: {{parVal}} {{childVal}} <br /> <button ng-click="changeVal()">Change</button></div>'
}
}
The variable parVal
from the parent directive's controller's scope gets handed down to the child directive's controller. The child directive has its own variable childVal
which is parVal + 1
. I try to change parVal
's value indirectly by emitting an event in the child directive. As expected, parVal
's value changes and is reflected in the View. However, childVal
's value is not changed.
I am able to see the updated value of childVal
using a $watch on parVal
. Is there any other way I can do this?
There are a few ways you can share code between these two directives.
One way is to take advantage of how firstDir
prototypically inherits from parentDir
. You're already doing that with parVal
, but you probably had issues updating parVal
from within the child directive. An easy workaround is to create an update function in the parent directive. This gives you access to update the scope directly. example: http://jsfiddle.net/T7W6T/4/
edit: I don't like the above approach because it tightly couples both directives and firstDir
won't work on it's own.
Another way is to create a shared service. A service in angular is a singleton, so anywhere it is injected into a controller will be the same instance as everywhere else. You can easily create a pub/sub mechanism. Just be sure to clean up the subscribers when the scope of the subscriber is destroyed. This is my preferred way to share between directives and controllers because you don't pollute your scope. Remember, everything bound to scope has an effect on the digest.
Example code of a minimal pub/sub mechanism:
myapp.service('SharedService', function(){
var listeners = [];
return {
publish: function(){
angular.forEach(listeners, function(listener){
listener.call(null);
});
},
subscribe: function(fn){
listeners.push(fn);
},
unsubscribe: function(fn){
var idx = listeners.indexOf(fn);
if(idx > -1){
listeners.splice(idx,1);
}
}
}
});
You interact with this from the parent directive like so:
var update = function(){
$scope.parVal = 200;
};
SharedService.subscribe(update);
$scope.$on("$destroy", function(){
SharedService.unsubscribe(update);
});
And the child directive is the only thing that can access the function to publish to listeners:
$scope.updateParVal = function(){
SharedService.publish();
};
There's a pretty good explanation on SO about whether scope inheritance or $emit
is better: https://stackoverflow.com/a/18179640/151445
One thing I don't usually see mentioned about the service approach is that you control exactly where subscribers and publishers are bound. With $scope.$emit
and $scope.$on
, anyone with a scope can go crazy with events.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.