Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

feat($compile): support directive virtual groups #2783

Merged
merged 1 commit into from
@mhevery
Owner

By appending X-start and X-end to a directive it is now possible
to have the directive act on a group of elements.

It is now possible to iterate over multiple elements like so:

<table>
  <tr ng-repeat-start="item in list">I get repeated</tr>
  <tr ng-repeat-end>I also get repeated</tr>
</table>
src/ng/compile.js
@@ -573,6 +587,47 @@ function $CompileProvider($provide) {
return directives;
}
+ /**
+ * Given a node witch a X-start it collects all of the siblings until it find X-end.
@petebacondarwin Owner

Typo: "witch a" -> "with an" or "which has an"

@mhevery Owner
mhevery added a note

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lrlopez

Cool! Just one comment: It may be necessary to state that this introduces a breaking change as any previous directive that ended with start won't work now without changes.

@mhevery mhevery feat($compile): support multi-element directive
By appending  directive-start and directive-end to a
directive it is now possible to have the directive
act on a group of elements.

It is now possible to iterate over multiple elements like so:

<table>
  <tr ng-repeat-start="item in list">I get repeated</tr>
  <tr ng-repeat-end>I also get repeated</tr>
</table>
e46100f
@mhevery mhevery merged commit e46100f into angular:master
@gevgeny

I have tried to run this example but got the error:
TypeError: Object #<Text> has no method 'hasAttribute'
at groupScan (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4730:20)
at applyDirectivesToNode (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4796:26)
at compileNodes (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4563:15)
at compileNodes (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4568:15)
at compileNodes (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4568:15)
at compileNodes (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4568:15)
at compileNodes (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4568:15)
at compileNodes (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4568:15)
at compile (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:4505:29)
at resumeBootstrapInternal (http://localhost:8889/examples/market-stats3/js/dependencies/angular.1.1.6-b6a0777.js:1009:11)

See details here: http://stackoverflow.com/questions/10457833/how-would-i-render-a-dynamic-definition-list-using-angular/16808545#16808545

@aleksabl

I've made a fix for this inn pull request #2859 .

@VonD

hi,
thanks for this great feature. Do you have an idea when this will be in the stable branch ?
thanks a lot.

That is super. We'll be watching for this on the mainline, too :+1: .

Nice change, I've got a couple of use cases for this.

Can not wait to use it!

AFICT, this doesn't help a case where you want nested repeats of different cardinality, e.g. in bastardized regex: (h4 p).

This is neato! One thought though - it is encroaching on what attributes you can and can't use - even when they are custom attributes.

kendo-labs/angular-kendo#203 (comment)

Is there a way to override this behavior (turn it on/off), or are we now going to have to change any start end named attributes?

Collaborator

@burkeholland There's a PR to provide a bit more control for this, #5372 --- for the time being, unfortunately you are stuck with it =(

@cdmckay

Wouldn't it make more sense to have a ngGroup directive that self-destructs after being added?

<table>
  <ng-group ng-repeat="item in list">
    <tr>I get repeated</tr>
    <tr>I also get repeated</tr>  
  </ng-group>
</table>

When ng-group renders, it always removes itself and adds it's children to its parent element.

@rodyhaddad rodyhaddad referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@rodyhaddad rodyhaddad referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@rodyhaddad rodyhaddad referenced this pull request from a commit in rodyhaddad/angular.js
@rodyhaddad rodyhaddad feat($compile): support multi-elements in all declaration styles
I've built on the work of #2783 to make multi-elements possible in all
directive decralation styles.
Basically #2783 was limited to directives declared via attributes.
With this commit, appending X-start and X-end would work
in Comments, Attributes, ClassNames and ElementNames
```html
<table>
  <!-- directive: ng-repeat-start item in list -->
    <tr>If ngRepeat's 'restrict' get changed to include 'M'</tr>
    <tr>I get repeated</tr>
  <!-- ng-repeat-end -->
</table>
```
72c7cc1
@rodyhaddad rodyhaddad referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@rodyhaddad rodyhaddad referenced this pull request from a commit in rodyhaddad/angular.js
@rodyhaddad rodyhaddad feat($compile): support multi-elements in all declaration styles
I've built on the work of #2783 to make multi-elements possible in all
directive decralation styles.
Basically #2783 was limited to directives declared via attributes.
With this commit, appending X-start and X-end would work
in Comments, Attributes, ClassNames and ElementNames
```html
<table>
  <!-- directive: ng-repeat-start item in list -->
    <tr>If ngRepeat's 'restrict' get changed to include 'M'</tr>
    <tr>I get repeated</tr>
  <!-- ng-repeat-end -->
</table>
```
c7f5c1e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 29, 2013
  1. @mhevery

    feat($compile): support multi-element directive

    mhevery authored
    By appending  directive-start and directive-end to a
    directive it is now possible to have the directive
    act on a group of elements.
    
    It is now possible to iterate over multiple elements like so:
    
    <table>
      <tr ng-repeat-start="item in list">I get repeated</tr>
      <tr ng-repeat-end>I also get repeated</tr>
    </table>
This page is out of date. Refresh to see the latest.
View
50 src/jqLite.js
@@ -165,7 +165,8 @@ function JQLite(element) {
div.innerHTML = '<div>&#160;</div>' + element; // IE insanity to make NoScope elements work!
div.removeChild(div.firstChild); // remove the superfluous div
JQLiteAddNodes(this, div.childNodes);
- this.remove(); // detach the elements from the temporary DOM div.
+ var fragment = jqLite(document.createDocumentFragment());
+ fragment.append(this); // detach the elements from the temporary DOM div.
} else {
JQLiteAddNodes(this, element);
}
@@ -456,24 +457,26 @@ forEach({
}
},
- text: extend((msie < 9)
- ? function(element, value) {
- if (element.nodeType == 1 /** Element */) {
- if (isUndefined(value))
- return element.innerText;
- element.innerText = value;
- } else {
- if (isUndefined(value))
- return element.nodeValue;
- element.nodeValue = value;
- }
+ text: (function() {
+ var NODE_TYPE_TEXT_PROPERTY = [];
+ if (msie < 9) {
+ NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/
+ NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/
+ } else {
+ NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
+ NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/
+ }
+ getText.$dv = '';
+ return getText;
+
+ function getText(element, value) {
+ var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType]
+ if (isUndefined(value)) {
+ return textProp ? element[textProp] : '';
}
- : function(element, value) {
- if (isUndefined(value)) {
- return element.textContent;
- }
- element.textContent = value;
- }, {$dv:''}),
+ element[textProp] = value;
+ }
+ })(),
val: function(element, value) {
if (isUndefined(value)) {
@@ -518,8 +521,14 @@ forEach({
return this;
} else {
// we are a read, so read the first child.
- if (this.length)
- return fn(this[0], arg1, arg2);
+ var value = fn.$dv;
+ // Only if we have $dv do we iterate over all, otherwise it is just the first element.
+ var jj = value == undefined ? Math.min(this.length, 1) : this.length;
+ for (var j = 0; j < jj; j++) {
+ var nodeValue = fn(this[j], arg1, arg2);
+ value = value ? value + nodeValue : nodeValue;
+ }
+ return value;
}
} else {
// we are a write, so apply to all children
@@ -529,7 +538,6 @@ forEach({
// return self for chaining
return this;
}
- return fn.$dv;
};
});
View
15 src/ng/animator.js
@@ -395,11 +395,16 @@ var $AnimatorProvider = function() {
}
function insert(element, parent, after) {
- if (after) {
- after.after(element);
- } else {
- parent.append(element);
- }
+ var afterNode = after && after[after.length - 1];
+ var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
+ var afterNextSibling = afterNode && afterNode.nextSibling;
+ forEach(element, function(node) {
+ if (afterNextSibling) {
+ parentNode.insertBefore(node, afterNextSibling);
+ } else {
+ parentNode.appendChild(node);
+ }
+ });
}
function remove(element) {
View
123 src/ng/compile.js
@@ -358,11 +358,12 @@ function $CompileProvider($provide) {
// jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
$compileNodes = jqLite($compileNodes);
}
+ var tempParent = document.createDocumentFragment();
// We can not compile top level text elements since text nodes can be merged and we will
// not be able to attach scope data to them, so we will wrap them in <span>
forEach($compileNodes, function(node, index){
if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
- $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
+ $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
}
});
var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
@@ -420,7 +421,7 @@ function $CompileProvider($provide) {
attrs = new Attributes();
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
- directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
+ directives = collectDirectives(nodeList[i], [], attrs, i == 0 ? maxPriority : undefined);
nodeLinkFn = (directives.length)
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
@@ -509,6 +510,10 @@ function $CompileProvider($provide) {
// iterate over the attributes
for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
+ var attrStartName;
+ var attrEndName;
+ var index;
+
attr = nAttrs[j];
if (attr.specified) {
name = attr.name;
@@ -517,6 +522,11 @@ 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());
attrsMap[nName] = name;
attrs[nName] = value = trim((msie && name == 'href')
@@ -526,7 +536,7 @@ function $CompileProvider($provide) {
attrs[nName] = true; // presence means true
}
addAttrInterpolateDirective(node, directives, value, nName);
- addDirective(directives, nName, 'A', maxPriority);
+ addDirective(directives, nName, 'A', maxPriority, attrStartName, attrEndName);
}
}
@@ -565,6 +575,47 @@ function $CompileProvider($provide) {
return directives;
}
+ /**
+ * Given a node with an directive-start it collects all of the siblings until it find directive-end.
+ * @param node
+ * @param attrStart
+ * @param attrEnd
+ * @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 ngError(51, "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd);
+ }
+ if (node.hasAttribute(attrStart)) depth++;
+ if (node.hasAttribute(attrEnd)) depth--;
+ nodes.push(node);
+ node = node.nextSibling;
+ } while (depth > 0);
+ } else {
+ nodes.push(node);
+ }
+ return jqLite(nodes);
+ }
+
+ /**
+ * Wrapper for linking function which converts normal linking function into a grouped
+ * linking function.
+ * @param linkFn
+ * @param attrStart
+ * @param attrEnd
+ * @returns {Function}
+ */
+ function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
+ return function(scope, element, attrs, controllers) {
+ element = groupScan(element[0], attrStart, attrEnd);
+ return linkFn(scope, element, attrs, controllers);
+ }
+ }
/**
* Once the directives have been collected, their compile functions are executed. This method
@@ -601,6 +652,13 @@ 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;
+
+ // collect multiblock sections
+ if (attrStart) {
+ $compileNode = groupScan(compileNode, attrStart, attrEnd)
+ }
$template = undefined;
if (terminalPriority > directive.priority) {
@@ -631,11 +689,11 @@ function $CompileProvider($provide) {
transcludeDirective = directive;
terminalPriority = directive.priority;
if (directiveValue == 'element') {
- $template = jqLite(compileNode);
+ $template = groupScan(compileNode, attrStart, attrEnd)
$compileNode = templateAttrs.$$element =
jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
compileNode = $compileNode[0];
- replaceWith(jqCollection, jqLite($template[0]), compileNode);
+ replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
childTranscludeFn = compile($template, transcludeFn, terminalPriority);
} else {
$template = jqLite(JQLiteClone(compileNode)).contents();
@@ -699,9 +757,9 @@ function $CompileProvider($provide) {
try {
linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
if (isFunction(linkFn)) {
- addLinkFns(null, linkFn);
+ addLinkFns(null, linkFn, attrStart, attrEnd);
} else if (linkFn) {
- addLinkFns(linkFn.pre, linkFn.post);
+ addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
}
} catch (e) {
$exceptionHandler(e, startingTag($compileNode));
@@ -723,12 +781,14 @@ function $CompileProvider($provide) {
////////////////////
- function addLinkFns(pre, post) {
+ function addLinkFns(pre, post, attrStart, attrEnd) {
if (pre) {
+ if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
pre.require = directive.require;
preLinkFns.push(pre);
}
if (post) {
+ if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
post.require = directive.require;
postLinkFns.push(post);
}
@@ -907,8 +967,8 @@ function $CompileProvider($provide) {
* * `M`: comment
* @returns true if directive was added.
*/
- function addDirective(tDirectives, name, location, maxPriority) {
- var match = false;
+ function addDirective(tDirectives, name, location, maxPriority, startAttrName, endAttrName) {
+ var match = null;
if (hasDirectives.hasOwnProperty(name)) {
for(var directive, directives = $injector.get(name + Suffix),
i = 0, ii = directives.length; i<ii; i++) {
@@ -916,8 +976,11 @@ 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});
+ }
tDirectives.push(directive);
- match = true;
+ match = directive;
}
} catch(e) { $exceptionHandler(e); }
}
@@ -1120,30 +1183,50 @@ function $CompileProvider($provide) {
*
* @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
* in the root of the tree.
- * @param {JqLite} $element The jqLite element which we are going to replace. We keep the shell,
+ * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep the shell,
* but replace its DOM node reference.
* @param {Node} newNode The new DOM node.
*/
- function replaceWith($rootElement, $element, newNode) {
- var oldNode = $element[0],
- parent = oldNode.parentNode,
+ function replaceWith($rootElement, elementsToRemove, newNode) {
+ var firstElementToRemove = elementsToRemove[0],
+ removeCount = elementsToRemove.length,
+ parent = firstElementToRemove.parentNode,
i, ii;
if ($rootElement) {
for(i = 0, ii = $rootElement.length; i < ii; i++) {
- if ($rootElement[i] == oldNode) {
- $rootElement[i] = newNode;
+ if ($rootElement[i] == firstElementToRemove) {
+ $rootElement[i++] = newNode;
+ for (var j = i, j2 = j + removeCount - 1,
+ jj = $rootElement.length;
+ j < jj; j++, j2++) {
+ if (j2 < jj) {
+ $rootElement[j] = $rootElement[j2];
+ } else {
+ delete $rootElement[j];
+ }
+ }
+ $rootElement.length -= removeCount - 1;
break;
}
}
}
if (parent) {
- parent.replaceChild(newNode, oldNode);
+ parent.replaceChild(newNode, firstElementToRemove);
+ }
+ var fragment = document.createDocumentFragment();
+ fragment.appendChild(firstElementToRemove);
+ newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
+ for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
+ var element = elementsToRemove[k];
+ jqLite(element).remove(); // must do this way to clean up expando
+ fragment.appendChild(element);
+ delete elementsToRemove[k];
}
- newNode[jqLite.expando] = oldNode[jqLite.expando];
- $element[0] = newNode;
+ elementsToRemove[0] = newNode;
+ elementsToRemove.length = 1
}
}];
}
View
2  src/ng/directive/ngRepeat.js
@@ -258,7 +258,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
if (lastBlockMap.hasOwnProperty(key)) {
block = lastBlockMap[key];
animate.leave(block.element);
- block.element[0][NG_REMOVED] = true;
+ forEach(block.element, function(element) { element[NG_REMOVED] = true});
block.scope.$destroy();
}
}
View
12 test/jqLiteSpec.js
@@ -56,6 +56,9 @@ describe('jqLite', function() {
it('should allow construction with html', function() {
var nodes = jqLite('<div>1</div><span>2</span>');
+ expect(nodes[0].parentNode).toBeDefined();
+ expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment **/;
+ expect(nodes[0].parentNode).toBe(nodes[1].parentNode);
expect(nodes.length).toEqual(2);
expect(nodes[0].innerHTML).toEqual('1');
expect(nodes[1].innerHTML).toEqual('2');
@@ -644,12 +647,13 @@ describe('jqLite', function() {
it('should read/write value', function() {
- var element = jqLite('<div>abc</div>');
- expect(element.length).toEqual(1);
- expect(element[0].innerHTML).toEqual('abc');
+ var element = jqLite('<div>ab</div><span>c</span>');
+ expect(element.length).toEqual(2);
+ expect(element[0].innerHTML).toEqual('ab');
+ expect(element[1].innerHTML).toEqual('c');
expect(element.text()).toEqual('abc');
expect(element.text('xyz') == element).toBeTruthy();
- expect(element.text()).toEqual('xyz');
+ expect(element.text()).toEqual('xyzxyz');
});
});
View
125 test/ng/compileSpec.js
@@ -2718,4 +2718,129 @@ describe('$compile', function() {
expect(element.attr('test4')).toBe('Misko');
}));
});
+
+
+ describe('multi-element directive', function() {
+ it('should group on link function', inject(function($compile, $rootScope) {
+ $rootScope.show = false;
+ element = $compile(
+ '<div>' +
+ '<span ng-show-start="show"></span>' +
+ '<span ng-show-end></span>' +
+ '</div>')($rootScope);
+ $rootScope.$digest();
+ var spans = element.find('span');
+ expect(spans.eq(0).css('display')).toBe('none');
+ expect(spans.eq(1).css('display')).toBe('none');
+ }));
+
+
+ it('should group on compile function', inject(function($compile, $rootScope) {
+ $rootScope.show = false;
+ element = $compile(
+ '<div>' +
+ '<span ng-repeat-start="i in [1,2]">{{i}}A</span>' +
+ '<span ng-repeat-end>{{i}}B;</span>' +
+ '</div>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('1A1B;2A2B;');
+ }));
+
+
+ it('should group on $root compile function', inject(function($compile, $rootScope) {
+ $rootScope.show = false;
+ element = $compile(
+ '<div></div>' +
+ '<span ng-repeat-start="i in [1,2]">{{i}}A</span>' +
+ '<span ng-repeat-end>{{i}}B;</span>' +
+ '<div></div>')($rootScope);
+ $rootScope.$digest();
+ element = jqLite(element[0].parentNode.childNodes); // reset because repeater is top level.
+ expect(element.text()).toEqual('1A1B;2A2B;');
+ }));
+
+
+ it('should group on nested groups', inject(function($compile, $rootScope) {
+ $rootScope.show = false;
+ element = $compile(
+ '<div></div>' +
+ '<div ng-repeat-start="i in [1,2]">{{i}}A</div>' +
+ '<span ng-bind-start="\'.\'"></span>' +
+ '<span ng-bind-end></span>' +
+ '<div ng-repeat-end>{{i}}B;</div>' +
+ '<div></div>')($rootScope);
+ $rootScope.$digest();
+ element = jqLite(element[0].parentNode.childNodes); // reset because repeater is top level.
+ expect(element.text()).toEqual('1A..1B;2A..2B;');
+ }));
+
+
+ it('should group on nested groups', inject(function($compile, $rootScope) {
+ $rootScope.show = false;
+ element = $compile(
+ '<div></div>' +
+ '<div ng-repeat-start="i in [1,2]">{{i}}(</div>' +
+ '<span ng-repeat-start="j in [2,3]">{{j}}-</span>' +
+ '<span ng-repeat-end>{{j}}</span>' +
+ '<div ng-repeat-end>){{i}};</div>' +
+ '<div></div>')($rootScope);
+ $rootScope.$digest();
+ element = jqLite(element[0].parentNode.childNodes); // reset because repeater is top level.
+ expect(element.text()).toEqual('1(2-23-3)1;2(2-23-3)2;');
+ }));
+
+
+ it('should throw error if unterminated', function () {
+ module(function($compileProvider) {
+ $compileProvider.directive('foo', function() {
+ return {
+ };
+ });
+ });
+ inject(function($compile, $rootScope) {
+ expect(function() {
+ element = $compile(
+ '<div>' +
+ '<span foo-start></span>' +
+ '</div>');
+ }).toThrow("[NgErr51] Unterminated attribute, 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, $rootScope) {
+ expect(function() {
+ element = $compile(
+ '<div>' +
+ '<span foo-start><span foo-end></span></span>' +
+ '</div>');
+ }).toThrow("[NgErr51] Unterminated attribute, found 'foo-start' but no matching 'foo-end' found.");
+ });
+ });
+
+
+ it('should support data- and x- prefix', inject(function($compile, $rootScope) {
+ $rootScope.show = false;
+ element = $compile(
+ '<div>' +
+ '<span data-ng-show-start="show"></span>' +
+ '<span data-ng-show-end></span>' +
+ '<span x-ng-show-start="show"></span>' +
+ '<span x-ng-show-end></span>' +
+ '</div>')($rootScope);
+ $rootScope.$digest();
+ var spans = element.find('span');
+ expect(spans.eq(0).css('display')).toBe('none');
+ expect(spans.eq(1).css('display')).toBe('none');
+ expect(spans.eq(2).css('display')).toBe('none');
+ expect(spans.eq(3).css('display')).toBe('none');
+ }));
+ });
});
Something went wrong with that request. Please try again.