diff options
| -rw-r--r-- | src/ng/compile.js | 2 | ||||
| -rw-r--r-- | src/ng/directive/ngIf.js | 35 | ||||
| -rwxr-xr-x | test/ng/directive/ngIfSpec.js | 37 |
3 files changed, 65 insertions, 9 deletions
diff --git a/src/ng/compile.js b/src/ng/compile.js index 7754a8e6..af7d5e6b 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1175,7 +1175,7 @@ function $CompileProvider($provide) { if (directiveValue = directive.transclude) { // Special case ngRepeat so that we don't complain about duplicate transclusion, ngRepeat // knows how to handle this on its own. - if (directiveName !== 'ngRepeat') { + if (directiveName !== 'ngRepeat' && directiveName !== 'ngIf') { assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode); transcludeDirective = directive; } diff --git a/src/ng/directive/ngIf.js b/src/ng/directive/ngIf.js index b2811ab4..662f3f32 100644 --- a/src/ng/directive/ngIf.js +++ b/src/ng/directive/ngIf.js @@ -86,20 +86,21 @@ var ngIfDirective = ['$animate', function($animate) { restrict: 'A', compile: function (element, attr, transclude) { return function ($scope, $element, $attr) { - var childElement, childScope; + var block = {}, childScope; $scope.$watch($attr.ngIf, function ngIfWatchAction(value) { - if (childElement) { - $animate.leave(childElement); - childElement = undefined; + if (block.startNode) { + $animate.leave(getBlockElements(block)); + block = {}; } - if (childScope) { - childScope.$destroy(); - childScope = undefined; + if (block.startNode) { + getBlockElements(block).$destroy(); + block = {}; } if (toBoolean(value)) { childScope = $scope.$new(); transclude(childScope, function (clone) { - childElement = clone; + block.startNode = clone[0]; + block.endNode = clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' '); $animate.enter(clone, $element.parent(), $element); }); } @@ -107,4 +108,22 @@ var ngIfDirective = ['$animate', function($animate) { }; } }; + + // TODO(bford): this helper was copypasta'd from ngRepeat + function getBlockElements(block) { + if (block.startNode === block.endNode) { + return jqLite(block.startNode); + } + + var element = block.startNode; + var elements = [element]; + + do { + element = element.nextSibling; + if (!element) break; + elements.push(element); + } while (element !== block.endNode); + + return jqLite(elements); + } }]; diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js index 79eab6bb..509cf26d 100755 --- a/test/ng/directive/ngIfSpec.js +++ b/test/ng/directive/ngIfSpec.js @@ -60,6 +60,43 @@ describe('ngIf', function () { expect(element.children().length).toBe(9); }); + it('should play nice with ngInclude on the same element', inject(function($templateCache) { + $templateCache.put('test.html', [200, '{{value}}', {}]); + + $scope.value = 'first'; + element.append($compile( + '<div ng-if="value==\'first\'" ng-include="\'test.html\'"></div>' + )($scope)); + $scope.$apply(); + expect(element.text()).toBe('first'); + + $scope.value = 'later'; + $scope.$apply(); + expect(element.text()).toBe(''); + })); + + it('should work with multiple elements', function() { + $scope.show = true; + $scope.things = [1, 2, 3]; + element.append($compile( + '<div>before;</div>' + + '<div ng-if-start="show">start;</div>' + + '<div ng-repeat="thing in things">{{thing}};</div>' + + '<div ng-if-end>end;</div>' + + '<div>after;</div>' + )($scope)); + $scope.$apply(); + expect(element.text()).toBe('before;start;1;2;3;end;after;'); + + $scope.things.push(4); + $scope.$apply(); + expect(element.text()).toBe('before;start;1;2;3;4;end;after;'); + + $scope.show = false; + $scope.$apply(); + expect(element.text()).toBe('before;after;'); + }); + it('should restore the element to its compiled state', function() { $scope.value = true; makeIf('value'); |
