fix(ngMessages): create new scope for ngMessage, clean it up correctly

Previously, ngMessage elements used the same scope as ngMessages. When ngMessage
has interpolation in the textContent, then removing the message would not remove
the watcher from the scope - it would only be removed when the whole ngMessages
element was removed.

This commit changes the ngMessage transclude function to create a new child scope
instead, which can be destroyed safely when the message element is removed and
the message is detached

Fixes #14307
PR (#14308)
This commit is contained in:
Martin Staffa
2016-06-10 14:45:36 +02:00
committed by GitHub
parent e9865654b3
commit 3360b44be6
2 changed files with 30 additions and 1 deletions
+2 -1
View File
@@ -684,7 +684,7 @@ function ngMessageDirectiveFactory() {
},
attach: function() {
if (!currentElement) {
$transclude(scope, function(elm) {
$transclude(function(elm, newScope) {
$animate.enter(elm, null, element);
currentElement = elm;
@@ -700,6 +700,7 @@ function ngMessageDirectiveFactory() {
ngMessagesCtrl.deregister(commentNode);
messageCtrl.detach();
}
newScope.$destroy();
});
});
}
+28
View File
@@ -609,6 +609,34 @@ describe('ngMessages', function() {
});
});
it('should clean-up the ngMessage scope when a message is removed',
inject(function($compile, $rootScope) {
var html =
'<div ng-messages="items">' +
'<div ng-message="a">{{forA}}</div>' +
'</div>';
element = $compile(html)($rootScope);
$rootScope.$apply(function() {
$rootScope.forA = 'A';
$rootScope.items = {a: true};
});
expect(element.text()).toBe('A');
var watchers = $rootScope.$countWatchers();
$rootScope.$apply('items.a = false');
expect(element.text()).toBe('');
// We don't know exactly how many watchers are on the scope, only that there should be
// one less now
expect($rootScope.$countWatchers()).toBe(watchers - 1);
})
);
describe('when including templates', function() {
they('should work with a dynamic collection model which is managed by ngRepeat',
{'<div ng-messages-include="...">': '<div ng-messages="item">' +