I have a directive that I would like to force render when a change is made to an underlying model programmatically. $scope.$apply
is idiomatic. But I am unable to get the directive to render without clicking repeatedly on the UI (which presumably manually forces the digest).
Can someone help me identify how to manually trigger the digest?
Even this.scope.$root.$apply()
has no effect.
Grabbing hold of a parent DOM node and getting the associated scope, then calling $apply
on that from the console, does work however.
When using this DOM node approach in the code it does not work however. Why might this be?
I have a directive that I would like to force render when a change is made to an underlying model programmatically. $scope.$apply
is idiomatic. But I am unable to get the directive to render without clicking repeatedly on the UI (which presumably manually forces the digest).
Can someone help me identify how to manually trigger the digest?
Even this.scope.$root.$apply()
has no effect.
Grabbing hold of a parent DOM node and getting the associated scope, then calling $apply
on that from the console, does work however.
When using this DOM node approach in the code it does not work however. Why might this be?
Share edited Aug 4, 2015 at 22:04 C1pher 1,9726 gold badges34 silver badges52 bronze badges asked Aug 4, 2015 at 15:26 Ben AstonBen Aston 55.8k69 gold badges220 silver badges349 bronze badges 02 Answers
Reset to default 4Two things to note:
- Scopes inherit from each other prototypically and form a tree. Scopes have a reference to $parent which can be used to traverse.
- A digest cycle is something that happens on a scope object. Ie.
$scope.$digest()
. This runs a digest on the scope, and then recursively does the same for all of the child scopes.$scope.$apply()
is like doing$rootScope.$digest()
. Since it starts at the root, it calls a digest on every other scope. So$apply
might be excessive.
To answer your question, scope.$parent.$digest()
will trigger a digest on scope
's parent.
But it seems that the triggering of the digest isn't actually your problem. $apply
will trigger digests on all scopes, so if that isn't working for you, I don't think your problem is simply that you need a digest to be triggered.
Perhaps you don't need the whole directive to re-render, but just need a part of it to update? If so, consider data binding to some shared service like this.
HTML
<div ng-app='app'>
<one></one>
<two></two>
</div>
JS
angular
.module('app', [])
.directive('one', function() {
return {
restrict: 'E',
scope: {},
template: "<input ng-model='shared.val'> {{ shared.val }}",
controller: function($scope, Shared) {
$scope.shared = Shared;
}
};
})
.directive('two', function() {
return {
restrict: 'E',
scope: {},
template: '<p> {{ shared.val }}</p>',
controller: function($scope, Shared) {
$scope.shared = Shared;
}
};
})
.factory('Shared', function() {
return {
val: ''
};
});
It somewhat depends. It sounds like $parent
is what you want to call. scope.$root
simply holds a reference to $rootScope
(not your parent element scope). Short answer - try the following...
scope.$parent.$apply()
Longer answer - the above assumes your child directive scope inherits from your parent via scope: true
. See SO answer How to access parent scope from within a custom directive with own scope in AngularJS? for more detail on the topic and other possible approaches to access the parent scope. Once you get a handle on your parent scope, just call $apply()
on it.
I've made an example which modifies the parent scope on a jQuery .click()
event. Consider the following and observe the parent behavior...
app.directive('parent', function() {
return {
link: function(scope, elem, attrs) {
scope.value = 'parent'
}
}
});
app.directive('child', function() {
return {
scope: true,
link: function(scope, elem, attrs) {
scope.value = 'child'
elem.click(function() {
scope.$parent.value = 'modded!!' // -- previously 'parent'
scope.$parent.$apply();
})
}
}
});
JSFiddle Link - working example