diff --git a/src/ng/compile.js b/src/ng/compile.js index 7a2ee4e7fcf8..f17f99891c42 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -152,6 +152,7 @@ function $CompileProvider($provide) { var hasDirectives = {}, Suffix = 'Directive', COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, + COMMENT_END_DIRECTIVE_REGEXP = /^\s*(?:directive\:)?\s*([\d\w\-_]+)\s*$/, CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/, imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//; @@ -601,20 +602,21 @@ function $CompileProvider($provide) { var nodeType = node.nodeType, attrsMap = attrs.$attr, match, - className; + className, + name, nName, + startName, endName; switch(nodeType) { case 1: /* Element */ // use the node name: - addDirective(directives, - directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective); + name = nodeName_(node).toLowerCase(); + nName = directiveNormalize(name); + handleStartEndName(name, nName); + addDirective(directives, nName, 'E', maxPriority, ignoreDirective, startName, endName); // iterate over the attributes - for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes, + for (var attr, ngAttrName, value, nAttrs = node.attributes, j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) { - var attrStartName; - var attrEndName; - var index; attr = nAttrs[j]; if (!msie || msie >= 8 || attr.specified) { @@ -624,12 +626,8 @@ function $CompileProvider($provide) { if (NG_ATTR_BINDING.test(ngAttrName)) { name = ngAttrName.substr(6).toLowerCase(); } - if ((index = ngAttrName.lastIndexOf('Start')) != -1 && index == ngAttrName.length - 5) { - attrStartName = name; - attrEndName = name.substr(0, name.length - 5) + 'end'; - name = name.substr(0, name.length - 6); - } nName = directiveNormalize(name.toLowerCase()); + handleStartEndName(name, nName); attrsMap[nName] = name; attrs[nName] = value = trim((msie && name == 'href') ? decodeURIComponent(node.getAttribute(name, 2)) @@ -638,7 +636,7 @@ function $CompileProvider($provide) { attrs[nName] = true; // presence means true } addAttrInterpolateDirective(node, directives, value, nName); - addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, attrEndName); + addDirective(directives, nName, 'A', maxPriority, ignoreDirective, startName, endName); } } @@ -646,8 +644,10 @@ function $CompileProvider($provide) { className = node.className; if (isString(className) && className !== '') { while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) { - nName = directiveNormalize(match[2]); - if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) { + name = match[2]; + nName = directiveNormalize(name); + handleStartEndName(name, nName); + if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective, startName, endName)) { attrs[nName] = trim(match[3]); } className = className.substr(match.index + match[0].length); @@ -661,8 +661,10 @@ function $CompileProvider($provide) { try { match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); if (match) { - nName = directiveNormalize(match[1]); - if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) { + name = match[1]; + nName = directiveNormalize(name); + handleStartEndName(name, nName); + if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective, startName, endName)) { attrs[nName] = trim(match[2]); } } @@ -675,48 +677,115 @@ function $CompileProvider($provide) { directives.sort(byPriority); return directives; + + // takes care of populating (or emptying) startName and endName + // Also changes `name` and `nName` in the external scope if necessary + function handleStartEndName(_name, _nName) { + var index; + if ((index = _nName.lastIndexOf('Start')) != -1 && index == _nName.length - 5) { + startName = _name; + endName = _name.substr(0, _name.length - 5) + 'end'; + name = _name.substr(0, _name.length - 6); + nName = directiveNormalize(name); + } else { + startName = endName = undefined; + } + return name; + } } /** * Given a node with an directive-start it collects all of the siblings until it find directive-end. * @param node - * @param attrStart - * @param attrEnd + * @param nameStart + * @param nameEnd + * @param location * @returns {*} */ - function groupScan(node, attrStart, attrEnd) { - var nodes = []; - var depth = 0; - if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) { - var startNode = node; - do { - if (!node) { - throw $compileMinErr('uterdir', "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd); - } - if (node.nodeType == 1 /** Element **/) { - if (node.hasAttribute(attrStart)) depth++; - if (node.hasAttribute(attrEnd)) depth--; - } - nodes.push(node); - node = node.nextSibling; - } while (depth > 0); - } else { - nodes.push(node); + function groupScan(node, nameStart, nameEnd, location) { + var nodes = [], + depth = 0, + $node, name; + if (nameStart) { + switch (location) { + case 'E': /* Element */ + do { + if (!node) { + throw $compileMinErr('uterdir', "Unterminated directive, found '{0}' but no matching '{1}' found.", nameStart, nameEnd); + } + if (node.nodeType == 1 /** Element **/) { + name = nodeName_(node).toLowerCase(); + if (name == nameStart) depth++; + if (name == nameEnd) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + break; + + case 'A': /* Attribute */ + if (node.hasAttribute && node.hasAttribute(nameStart)) { + do { + if (!node) { + throw $compileMinErr('uterdir', "Unterminated directive, found '{0}' but no matching '{1}' found.", nameStart, nameEnd); + } + if (node.nodeType == 1 /** Element **/) { + if (node.hasAttribute(nameStart)) depth++; + if (node.hasAttribute(nameEnd)) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + } + break; + + case 'C': /* Class */ + do { + if (!node) { + throw $compileMinErr('uterdir', "Unterminated directive, found '{0}' but no matching '{1}' found.", nameStart, nameEnd); + } + if (node.nodeType == 1 /** Element **/) { + $node = jqLite(node); + if ($node.hasClass(nameStart) || $node.hasClass(nameStart + ":")) depth++; + if ($node.hasClass(nameEnd)) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + break; + + case 'M': /* Comment */ + do { + if (!node) { + throw $compileMinErr('uterdir', "Unterminated directive, found '{0}' but no matching '{1}' found.", nameStart, nameEnd); + } + if (node.nodeType == 8 /** Comment **/) { + name = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); + if (name && name[1] == nameStart) depth++; + name = COMMENT_END_DIRECTIVE_REGEXP.exec(node.nodeValue); + if (name && name[1] == nameEnd) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + break; + } } - return jqLite(nodes); + return jqLite(nodes.length ? nodes : node); } /** * Wrapper for linking function which converts normal linking function into a grouped * linking function. * @param linkFn - * @param attrStart - * @param attrEnd + * @param nameStart + * @param nameEnd + * @param location * @returns {Function} */ - function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { + function groupElementsLinkFnWrapper(linkFn, nameStart, nameEnd, location) { return function(scope, element, attrs, controllers) { - element = groupScan(element[0], attrStart, attrEnd); + element = groupScan(element[0], nameStart, nameEnd, location); return linkFn(scope, element, attrs, controllers); } } @@ -757,12 +826,12 @@ function $CompileProvider($provide) { // executes all directives on the current element for(var i = 0, ii = directives.length; i < ii; i++) { directive = directives[i]; - var attrStart = directive.$$start; - var attrEnd = directive.$$end; + var nameStart = directive.$$start; + var nameEnd = directive.$$end; // collect multiblock sections - if (attrStart) { - $compileNode = groupScan(compileNode, attrStart, attrEnd) + if (nameStart) { + $compileNode = groupScan(compileNode, nameStart, nameEnd, directive.$$location) } $template = undefined; @@ -794,7 +863,7 @@ function $CompileProvider($provide) { transcludeDirective = directive; terminalPriority = directive.priority; if (directiveValue == 'element') { - $template = groupScan(compileNode, attrStart, attrEnd) + $template = groupScan(compileNode, nameStart, nameEnd, directive.$$location); $compileNode = templateAttrs.$$element = jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' ')); compileNode = $compileNode[0]; @@ -868,9 +937,9 @@ function $CompileProvider($provide) { try { linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); if (isFunction(linkFn)) { - addLinkFns(null, linkFn, attrStart, attrEnd); + addLinkFns(null, linkFn, nameStart, nameEnd, directive.$$location); } else if (linkFn) { - addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd); + addLinkFns(linkFn.pre, linkFn.post, nameStart, nameEnd, directive.$$location); } } catch (e) { $exceptionHandler(e, startingTag($compileNode)); @@ -892,14 +961,14 @@ function $CompileProvider($provide) { //////////////////// - function addLinkFns(pre, post, attrStart, attrEnd) { + function addLinkFns(pre, post, nameStart, nameEnd, location) { if (pre) { - if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); + if (nameStart) pre = groupElementsLinkFnWrapper(pre, nameStart, nameEnd, location); pre.require = directive.require; preLinkFns.push(pre); } if (post) { - if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); + if (nameStart) post = groupElementsLinkFnWrapper(post, nameStart, nameEnd, location); post.require = directive.require; postLinkFns.push(post); } @@ -1082,7 +1151,7 @@ function $CompileProvider($provide) { * * `M`: comment * @returns true if directive was added. */ - function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, endAttrName) { + function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startName, endName) { if (name === ignoreDirective) return null; var match = null; if (hasDirectives.hasOwnProperty(name)) { @@ -1092,8 +1161,8 @@ function $CompileProvider($provide) { directive = directives[i]; if ( (maxPriority === undefined || maxPriority > directive.priority) && directive.restrict.indexOf(location) != -1) { - if (startAttrName) { - directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName}); + if (startName) { + directive = inherit(directive, {$$start: startName, $$end: endName, $$location: location}); } tDirectives.push(directive); match = directive; diff --git a/src/ng/directive/ngIf.js b/src/ng/directive/ngIf.js index 87c976a9f758..907ef8819612 100755 --- a/src/ng/directive/ngIf.js +++ b/src/ng/directive/ngIf.js @@ -82,7 +82,7 @@ var ngIfDirective = ['$animate', function($animate) { transclude: 'element', priority: 1000, terminal: true, - restrict: 'A', + restrict: 'AM', compile: function (element, attr, transclude) { return function ($scope, $element, $attr) { var childElement, childScope; diff --git a/src/ng/directive/ngRepeat.js b/src/ng/directive/ngRepeat.js index 50be2a618e68..b2a2a4ca55cb 100644 --- a/src/ng/directive/ngRepeat.js +++ b/src/ng/directive/ngRepeat.js @@ -214,6 +214,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { transclude: 'element', priority: 1000, terminal: true, + restrict: 'AM', compile: function(element, attr, linker) { return function($scope, $element, $attr){ var expression = $attr.ngRepeat; diff --git a/src/ng/directive/ngShowHide.js b/src/ng/directive/ngShowHide.js index 6b5ea3a21aa6..f1a84b4cfb3d 100644 --- a/src/ng/directive/ngShowHide.js +++ b/src/ng/directive/ngShowHide.js @@ -144,11 +144,14 @@ */ var ngShowDirective = ['$animate', function($animate) { - return function(scope, element, attr) { - scope.$watch(attr.ngShow, function ngShowWatchAction(value){ - $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide'); - }); - }; + return { + restrict: 'AM', + link: function(scope, element, attr) { + scope.$watch(attr.ngShow, function ngShowWatchAction(value){ + $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide'); + }); + } + } }]; @@ -296,9 +299,12 @@ var ngShowDirective = ['$animate', function($animate) { */ var ngHideDirective = ['$animate', function($animate) { - return function(scope, element, attr) { - scope.$watch(attr.ngHide, function ngHideWatchAction(value){ - $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide'); - }); - }; + return { + restrict: 'AM', + link: function(scope, element, attr) { + scope.$watch(attr.ngHide, function ngHideWatchAction(value){ + $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide'); + }); + } + } }]; diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index ba94c48bbfcf..5722ac4dd0f9 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -3252,6 +3252,150 @@ describe('$compile', function() { describe('multi-element directive', function() { + + function expectNodesToBe(nodes, description) { + expect(nodes.length).toBe(description.length); + forEach(nodes, function (node, i) { + forEach(description[i], function (value, key) { + switch (key) { + case "nodeType": + expect(node.nodeType).toBe(value); + break; + case "tagName": + expect(node.tagName.toLowerCase()).toBe(value); + break; + case "nodeValue": + expect(node.nodeValue).toBe(value); + break; + case "className": + expect(node.className).toBe(value); + break; + case "html": + expect(node.innerHTML).toBe(value); + break; + case "attr": + forEach(value, function (attrValue, attrName) { + expect(node.getAttribute(attrName)).toBe(attrValue); + }); + break; + } + }); + }); + } + + describe('should group elements and pass them correctly to directives', function () { + var compileEl, linkEl; + beforeEach(module(function($compileProvider) { + compileEl = linkEl = undefined; + $compileProvider.directive('foo', valueFn({ + restrict: 'ECMA', + compile: function (_compileEl) { + compileEl = _compileEl; + return function (scope, _linkEl) { + linkEl = _linkEl; + } + } + })); + })); + + //element, attributes, classes and comments + it('if the X-start/X-end are declared as attributes', inject(function ($compile, $rootScope) { + $rootScope.test = "middle"; + element = $compile( + '
' + + '' + + '{{ test }}' + + ''+ + '
' + )($rootScope); + + var expectedNodes = [ + {tagName: "span", attr: {"foo-start": ""}, nodeType: 1}, + {tagName: "span", html: "{{ test }}", nodeType: 1}, + {tagName: "span", attr: {"foo-end": ""}, nodeType: 1} + ]; + + expectNodesToBe(compileEl, expectedNodes); + $rootScope.$digest(); + expectedNodes[1].html = "middle"; + expectNodesToBe(linkEl, expectedNodes); + })); + + it('if the X-start/X-end are declared as comments', inject(function ($compile, $rootScope) { + $rootScope.test = "middle"; + element = $compile( + '
' + + '' + + '{{ test }}1' + + '{{ test }}2' + + '' + + '
' + )($rootScope); + + var expectedNodes = [ + {nodeValue: " directive: foo-start ", nodeType: 8}, + {tagName: "span", html: "{{ test }}1", nodeType: 1}, + {tagName: "span", html: "{{ test }}2", nodeType: 1}, + {nodeValue: " foo-end ", nodeType: 8} + ]; + + expectNodesToBe(compileEl, expectedNodes); + $rootScope.$digest(); + expectedNodes[1].html = "middle1"; + expectedNodes[2].html = "middle2"; + expectNodesToBe(compileEl, expectedNodes); + })); + + it('if the X-start/X-end are declared as classes', inject(function ($compile, $rootScope) { + $rootScope.test = "middle"; + element = $compile( + '
' + + '' + + '{{ test }}' + + ''+ + '
' + )($rootScope); + + var expectedNodes = [ + {tagName: "span", className: "foo-start", nodeType: 1}, + {tagName: "span", html: "{{ test }}", nodeType: 1}, + {tagName: "span", className: "foo-end", nodeType: 1} + ]; + + expectNodesToBe(compileEl, expectedNodes); + $rootScope.$digest(); + expectedNodes[1].html = "middle"; + expectNodesToBe(linkEl, expectedNodes); + })); + + + it('if the X-start/X-end are declared as elements', inject(function ($compile, $rootScope) { + // Creating elements using DOM methods allows us to avoid + // IE's HTML parser problems with custom tagNames + var div = document.createElement("div"), + span = document.createElement("span"); + div.appendChild(document.createElement("foo-start")); // + span.innerHTML = "{{ test }}"; + div.appendChild(span); // {{ test }} + div.appendChild(document.createElement("foo-end")); // + + $rootScope.test = "middle"; + element = $compile(div)($rootScope); + + var expectedNodes = [ + {tagName: "foo-start", nodeType: 1}, + {tagName: "span", html: "{{ test }}", nodeType: 1}, + {tagName: "foo-end", nodeType: 1} + ]; + + expectNodesToBe(compileEl, expectedNodes); + $rootScope.$digest(); + expectedNodes[1].html = "middle"; + expectNodesToBe(linkEl, expectedNodes); + })); + + }); + it('should group on link function', inject(function($compile, $rootScope) { $rootScope.show = false; element = $compile( @@ -3336,37 +3480,30 @@ describe('$compile', function() { it('should throw error if unterminated', function () { module(function($compileProvider) { - $compileProvider.directive('foo', function() { - return { - }; - }); + $compileProvider.directive('foo', valueFn({restrict: 'ECMA'})); }); - inject(function($compile, $rootScope) { - expect(function() { - element = $compile( + inject(function($compile) { + forEach([ + '', + '', + '', + '', + + '', + '', + '', + '' + ], function (node) { + + expect(function () { + element = $compile( '
' + - '' + - '
'); - }).toThrow("[$compile:uterdir] Unterminated attribute, found 'foo-start' but no matching 'foo-end' found."); - }); - }); + node + + ''); + }).toThrow("[$compile:uterdir] Unterminated directive, found 'foo-start' but no matching 'foo-end' found."); - - it('should throw error if unterminated', function () { - module(function($compileProvider) { - $compileProvider.directive('foo', function() { - return { - }; }); }); - inject(function($compile) { - expect(function() { - element = $compile( - '
' + - '' + - '
'); - }).toThrow("[$compile:uterdir] Unterminated attribute, found 'foo-start' but no matching 'foo-end' found."); - }); }); @@ -3386,6 +3523,7 @@ describe('$compile', function() { expect(spans.eq(2)).toBeHidden(); expect(spans.eq(3)).toBeHidden(); })); + }); describe('$animate animation hooks', function() { diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js index 79eab6bb2a11..e24cb0248527 100755 --- a/test/ng/directive/ngIfSpec.js +++ b/test/ng/directive/ngIfSpec.js @@ -73,6 +73,38 @@ describe('ngIf', function () { expect(element.children()[0].className).toContain('my-class'); }); + it('should work with multi-nodes declared as attributes', function () { + $scope.value = false; + element.append($compile( + '
' + + '
' + + '
' + + '
' + )($scope)); + $scope.$apply(); + expect(element.children().length).toBe(0); + $scope.$apply('value = true'); + expect(element.children().length).toBe(4); + $scope.$apply('value = false'); + expect(element.children().length).toBe(0); + }); + + it('should work with multi-nodes declared as comments', function () { + $scope.value = false; + element.append($compile( + '' + + '
' + + '
' + + '' + )($scope)); + $scope.$apply(); + expect(element.children().length).toBe(0); + $scope.$apply('value = true'); + expect(element.children().length).toBe(2); + $scope.$apply('value = false'); + expect(element.children().length).toBe(0); + }); + }); describe('ngIf animations', function () { diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js index 35b9f8976d15..6bef57e4e5ad 100644 --- a/test/ng/directive/ngRepeatSpec.js +++ b/test/ng/directive/ngRepeatSpec.js @@ -843,25 +843,48 @@ describe('ngRepeat', function() { }); }); - it('should grow multi-node repeater', inject(function($compile, $rootScope) { - $rootScope.show = false; - $rootScope.books = [ - {title:'T1', description: 'D1'}, - {title:'T2', description: 'D2'} - ]; - element = $compile( + describe('should grow multi-node repeater', function () { + it('when declared as attributes', inject(function($compile, $rootScope) { + $rootScope.show = false; + $rootScope.books = [ + {title:'T1', description: 'D1'}, + {title:'T2', description: 'D2'} + ]; + element = $compile( '
' + - '
{{book.title}}:
' + - '
{{book.description}};
' + - '
')($rootScope); + '
{{book.title}}:
' + + '
{{book.description}};
' + - $rootScope.$digest(); - expect(element.text()).toEqual('T1:D1;T2:D2;'); - $rootScope.books.push({title:'T3', description: 'D3'}); - $rootScope.$digest(); - expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;'); - })); + '')($rootScope); + + $rootScope.$digest(); + expect(element.text()).toEqual('T1:D1;T2:D2;'); + $rootScope.books.push({title:'T3', description: 'D3'}); + $rootScope.$digest(); + expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;'); + })); + + it('when declared as comments', inject(function($compile, $rootScope) { + $rootScope.show = false; + $rootScope.books = [ + {title:'T1', description: 'D1'}, + {title:'T2', description: 'D2'} + ]; + element = $compile( + '
' + + '' + + '
{{book.title}}:
' + + '
{{book.description}};
' + + '' + + '
')($rootScope); + $rootScope.$digest(); + expect(element.text()).toEqual('T1:D1;T2:D2;'); + $rootScope.books.push({title:'T3', description: 'D3'}); + $rootScope.$digest(); + expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;'); + })); + }); }); diff --git a/test/ng/directive/ngShowHideSpec.js b/test/ng/directive/ngShowHideSpec.js index 4a8e55da386e..13979706c751 100644 --- a/test/ng/directive/ngShowHideSpec.js +++ b/test/ng/directive/ngShowHideSpec.js @@ -3,7 +3,6 @@ describe('ngShow / ngHide', function() { var element; - afterEach(function() { dealoc(element); }); @@ -28,6 +27,22 @@ describe('ngShow / ngHide', function() { $rootScope.$digest(); expect(element).toBeShown(); })); + + it('should work with multi-nodes declared as attributes', multiNodeTests( + 'ngShow', + '
' + + '
' + + '
' + + '
' + )); + + it('should work with multi-nodes declared as comment', multiNodeTests( + 'ngShow', + '' + + '
' + + '
' + + '' + )); }); describe('ngHide', function() { @@ -39,7 +54,39 @@ describe('ngShow / ngHide', function() { $rootScope.$digest(); expect(element).toBeHidden(); })); + + it('should work with multi-nodes declared as attributes', multiNodeTests( + 'ngHide', + '
' + + '
' + + '
' + + '
' + )); + + it('should work with multi-nodes declared as comment', multiNodeTests( + 'ngHide', + '' + + '
' + + '
' + + '' + )); }); + + function multiNodeTests(directive, html) { + return inject(function($rootScope, $compile) { + element = jqLite('
').html(html); + element = $compile(element)($rootScope); + $rootScope.$digest(); + forEach(element.children(), function (element) { + expect(element)[directive == 'ngShow' ? 'toBeHidden' : 'toBeShown'](); + }); + $rootScope.exp = true; + $rootScope.$digest(); + forEach(element.children(), function (element) { + expect(element)[directive == 'ngShow' ? 'toBeShown' : 'toBeHidden'](); + }); + }) + } }); describe('ngShow / ngHide animations', function() {