From cbc81b90c7b9491acd1edad82e4f6414948bf836 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Wed, 23 Mar 2016 15:20:31 +0100 Subject: [PATCH] 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 --- src/ngMessages/messages.js | 3 ++- test/ngMessages/messagesSpec.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/ngMessages/messages.js b/src/ngMessages/messages.js index 8805eea81945..6ed575da879c 100644 --- a/src/ngMessages/messages.js +++ b/src/ngMessages/messages.js @@ -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(); }); }); } diff --git a/test/ngMessages/messagesSpec.js b/test/ngMessages/messagesSpec.js index 79457fa0276b..5bfbb0898c0d 100644 --- a/test/ngMessages/messagesSpec.js +++ b/test/ngMessages/messagesSpec.js @@ -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 = + '
' + + '
{{forA}}
' + + '
'; + + 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', {'
': '
' +