diff --git a/lib/core_dom/directive.dart b/lib/core_dom/directive.dart
index 1a8bfada6..c61ba5e90 100644
--- a/lib/core_dom/directive.dart
+++ b/lib/core_dom/directive.dart
@@ -17,10 +17,18 @@ class NodeAttrs {
NodeAttrs(this.element);
- operator [](String attributeName) =>
- element.attributes[attributeName];
+ operator [](String attributeName) {
+ var value = element.attributes[attributeName];
+ if (value == null && attributeName.startsWith('ng-')) {
+ value = element.attributes['data-$attributeName'];
+ }
+ return value;
+ }
operator []=(String attributeName, String value) {
+ if (attributeName.startsWith('ng-')) {
+ element.attributes.remove('data-$attributeName');
+ }
if (value == null) {
element.attributes.remove(attributeName);
} else {
diff --git a/lib/core_dom/selector.dart b/lib/core_dom/selector.dart
index 83c69ac66..8e8ace6f8 100644
--- a/lib/core_dom/selector.dart
+++ b/lib/core_dom/selector.dart
@@ -28,6 +28,31 @@ part of angular.core.dom;
*/
typedef List DirectiveSelector(dom.Node node);
+String _normalizeKey(String key) =>
+ key.startsWith('data-ng-') ? key.substring('data-'.length) : key;
+
+class _AttrValueMap implements Map {
+ var _map = {};
+
+ void addAll(Map other) { _map.addAll(other); }
+ bool containsKey(String key) => _map.containsKey(_normalizeKey(key));
+ bool containsValue(Object value) => _map.containsValue(value);
+ void clear() { _map.clear(); }
+ void forEach(Function f) { _map.forEach(f); }
+ V putIfAbsent(String key, Function ifAbsent) =>
+ _map.putIfAbsent(_normalizeKey(key), ifAbsent);
+ V remove(String key) => _map.remove(_normalizeKey(key));
+
+ V operator[](String key) => _map[_normalizeKey(key)];
+ void operator[]=(String key, V value) { _map[_normalizeKey(key)] = value; }
+
+ bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
+ int get length => _map.length;
+ Iterable get keys => _map.keys;
+ Iterable get values => _map.values;
+}
+
class _Directive {
final Type type;
final NgAnnotation annotation;
@@ -76,7 +101,6 @@ class _SelectorPart {
: element;
}
-
class _ElementSelector {
final String name;
@@ -86,8 +110,8 @@ class _ElementSelector {
var classMap = >{};
var classPartialMap = {};
- var attrValueMap = >>{};
- var attrValuePartialMap = >{};
+ var attrValueMap = new _AttrValueMap>>();
+ var attrValuePartialMap = new _AttrValueMap>();
_ElementSelector(this.name);
@@ -175,7 +199,7 @@ class _ElementSelector {
dom.Node node, String attrName,
String attrValue) {
- String matchingKey = _matchingKey(attrValueMap.keys, attrName);
+ String matchingKey = _matchingKey(attrValueMap.keys, _normalizeKey(attrName));
if (matchingKey != null) {
Map> valuesMap = attrValueMap[matchingKey];
@@ -306,6 +330,8 @@ DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {
// we need to pass the name to the directive by prefixing it to
// the value. Yes it is a bit of a hack.
directives[selectorRegExp.annotation].forEach((type) {
+ if (attrName.startsWith('data-ng-'))
+ attrName = attrName.substring('data-'.length);
directiveRefs.add(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
});
diff --git a/lib/directive/ng_cloak.dart b/lib/directive/ng_cloak.dart
index a661af8e5..ab2caae82 100644
--- a/lib/directive/ng_cloak.dart
+++ b/lib/directive/ng_cloak.dart
@@ -27,6 +27,7 @@ part of angular.directive;
class NgCloakDirective {
NgCloakDirective(dom.Element element) {
element.attributes.remove('ng-cloak');
+ element.attributes.remove('data-ng-cloak');
element.classes.remove('ng-cloak');
}
}
diff --git a/lib/directive/ng_src_boolean.dart b/lib/directive/ng_src_boolean.dart
index f2d57ead6..e9d8812a7 100644
--- a/lib/directive/ng_src_boolean.dart
+++ b/lib/directive/ng_src_boolean.dart
@@ -95,9 +95,15 @@ class NgAttributeDirective implements NgAttachAware {
void attach() {
String ngAttrPrefix = 'ng-attr-';
+ String dataNgAttrPrefix = 'data-ng-attr-';
_attrs.forEach((key, value) {
+ var newKey;
if (key.startsWith(ngAttrPrefix)) {
- var newKey = key.substring(ngAttrPrefix.length);
+ newKey = key.substring(ngAttrPrefix.length);
+ } else if (key.startsWith(dataNgAttrPrefix)) {
+ newKey = key.substring(dataNgAttrPrefix.length);
+ }
+ if (newKey != null) {
_attrs[newKey] = value;
_attrs.observe(key, (newValue) => _attrs[newKey] = newValue );
}
diff --git a/test/core_dom/directive_spec.dart b/test/core_dom/directive_spec.dart
index 26330eb00..9728eff9b 100644
--- a/test/core_dom/directive_spec.dart
+++ b/test/core_dom/directive_spec.dart
@@ -10,16 +10,21 @@ main() {
beforeEach(inject((TestBed tb) {
_ = tb;
- element = _.compile('
');
+ element = _.compile('
');
nodeAttrs = new NodeAttrs(element);
}));
- it('should transform names to camel case', () {
+ it('should return attribute value', () {
expect(nodeAttrs['foo']).toEqual('bar');
expect(nodeAttrs['foo-bar']).toEqual('baz');
expect(nodeAttrs['foo-bar-baz']).toEqual('foo');
});
+ it('should ignore data prefix', () {
+ expect(nodeAttrs['data-ng-qux']).toEqual('qux');
+ expect(nodeAttrs['ng-qux']).toEqual('qux');
+ });
+
it('should return null for unexistent attributes', () {
expect(nodeAttrs['baz']).toBeNull();
});
@@ -27,7 +32,7 @@ main() {
it('should provide a forEach function to iterate over attributes', () {
Map attrMap = new Map();
nodeAttrs.forEach((k, v) => attrMap[k] = v);
- expect(attrMap).toEqual({'foo': 'bar', 'foo-bar': 'baz', 'foo-bar-baz': 'foo'});
+ expect(attrMap).toEqual({'foo': 'bar', 'foo-bar': 'baz', 'foo-bar-baz': 'foo', 'data-ng-qux': 'qux'});
});
it('should provide a contains method', () {
@@ -38,7 +43,7 @@ main() {
});
it('should return the attribute names', () {
- expect(nodeAttrs.keys.toList()..sort()).toEqual(['foo', 'foo-bar', 'foo-bar-baz']);
+ expect(nodeAttrs.keys.toList()..sort()).toEqual(['data-ng-qux', 'foo', 'foo-bar', 'foo-bar-baz']);
});
});
}
diff --git a/test/core_dom/selector_spec.dart b/test/core_dom/selector_spec.dart
index f77975d3c..6165a2da6 100644
--- a/test/core_dom/selector_spec.dart
+++ b/test/core_dom/selector_spec.dart
@@ -30,6 +30,7 @@ import '../_specs.dart';
@NgDirective(selector: '[two-directives]') class _OneOfTwoDirectives {}
@NgDirective(selector: '[two-directives]') class _TwoOfTwoDirectives {}
+@NgDirective(selector:'[ng-directive]') class _NgDirectiveAttr{}
main() {
describe('Selector', () {
@@ -60,7 +61,8 @@ main() {
..type(_IgnoreChildren)
..type(_TwoDirectives)
..type(_OneOfTwoDirectives)
- ..type(_TwoOfTwoDirectives);
+ ..type(_TwoOfTwoDirectives)
+ ..type(_NgDirectiveAttr);
}));
beforeEach(inject((DirectiveMap directives) {
selector = directiveSelectorFactory(directives);
@@ -195,6 +197,18 @@ main() {
{ "selector": '[two-directives]', "value": '', "element": element}
]));
});
+
+ it('should match directive on [data-ng-attribute] ignoring data prefix', () {
+ expect(selector(element = e('
')),
+ toEqualsDirectiveInfos([
+ { "selector": '[ng-directive]', "value": 'abc', "element": element,
+ "name": 'ng-directive' }]));
+
+ expect(selector(element = e('
')),
+ toEqualsDirectiveInfos([
+ { "selector": '[ng-directive]', "value": '', "element": element,
+ "name": 'ng-directive' }]));
+ });
});
}
diff --git a/test/directive/ng_a_spec.dart b/test/directive/ng_a_spec.dart
index 5a8fd0fb6..f64e720d9 100644
--- a/test/directive/ng_a_spec.dart
+++ b/test/directive/ng_a_spec.dart
@@ -42,5 +42,12 @@ main() {
_.triggerEvent(_.rootElement, 'click', 'MouseEvent');
expect(window.location.href.endsWith("#url")).toEqual(true);
}));
+
+ it('should bind click listener with data attribute', inject((Scope scope) {
+ _.compile(' ');
+ _.triggerEvent(_.rootElement, 'click', 'MouseEvent');
+ expect(_.rootScope.context['abc']).toEqual(true);
+ expect(_.rootScope.context['event'] is dom.UIEvent).toEqual(true);
+ }));
});
}
diff --git a/test/directive/ng_bind_html_spec.dart b/test/directive/ng_bind_html_spec.dart
index 791bc7df0..8f077b316 100644
--- a/test/directive/ng_bind_html_spec.dart
+++ b/test/directive/ng_bind_html_spec.dart
@@ -34,6 +34,16 @@ main() {
expect(element.html()).toEqual('Google! ');
});
}));
+
+ it('should sanitize and set innerHtml and sanitize and set html with data attribute',
+ inject((Scope scope, Injector injector, Compiler compiler, DirectiveMap directives) {
+ var element = $('
');
+ compiler(element, directives)(injector, element);
+ scope.context['htmlVar'] = 'Google! ';
+ scope.apply();
+ // Sanitization removes the href attribute on the tag.
+ expect(element.html()).toEqual(' Google! ');
+ }));
});
}
diff --git a/test/directive/ng_bind_spec.dart b/test/directive/ng_bind_spec.dart
index f08509d7e..8432242a7 100644
--- a/test/directive/ng_bind_spec.dart
+++ b/test/directive/ng_bind_spec.dart
@@ -35,5 +35,13 @@ main() {
});
expect(element.text).toEqual('1');
}));
+
+ it('should set.text with data attribute', inject((Scope scope, Injector injector, Compiler compiler, DirectiveMap directives) {
+ var element = $('
');
+ compiler(element, directives)(injector, element);
+ scope.context['a'] = "abc123";
+ scope.apply();
+ expect(element.text()).toEqual('abc123');
+ }));
});
}
diff --git a/test/directive/ng_bind_template_spec.dart b/test/directive/ng_bind_template_spec.dart
index aad7af02d..a9e517463 100644
--- a/test/directive/ng_bind_template_spec.dart
+++ b/test/directive/ng_bind_template_spec.dart
@@ -22,5 +22,20 @@ main() {
expect(element.text).toEqual('Good-Bye Heisenberg!');
}));
+
+ it('should bind template with data attribute',
+ inject((Scope scope, Injector injector, Compiler compiler) {
+ var element = _.compile('
');
+ scope.context['salutation'] = 'Hello';
+ scope.context['name'] = 'Heisenberg';
+ scope.apply();
+
+ expect(element.text).toEqual('Hello Heisenberg!');
+
+ scope.context['salutation'] = 'Good-Bye';
+ scope.apply();
+
+ expect(element.text).toEqual('Good-Bye Heisenberg!');
+ }));
});
}
diff --git a/test/directive/ng_class_spec.dart b/test/directive/ng_class_spec.dart
index 9d6914a46..0f29d7b16 100644
--- a/test/directive/ng_class_spec.dart
+++ b/test/directive/ng_class_spec.dart
@@ -308,5 +308,25 @@ main() {
expect(e2.classes.contains('even')).toBeTruthy();
expect(e2.classes.contains('odd')).toBeFalsy();
});
+
+ it('should add new and remove old classes dynamically with data attribute', () {
+ var element = _.compile('
');
+ _.rootScope.context['dynClass'] = 'A';
+ _.rootScope.apply();
+ expect(element.classes.contains('existing')).toBe(true);
+ expect(element.classes.contains('A')).toBe(true);
+
+ _.rootScope.context['dynClass'] = 'B';
+ _.rootScope.apply();
+ expect(element.classes.contains('existing')).toBe(true);
+ expect(element.classes.contains('A')).toBe(false);
+ expect(element.classes.contains('B')).toBe(true);
+
+ _.rootScope.context['dynClass'] = null;
+ _.rootScope.apply();
+ expect(element.classes.contains('existing')).toBe(true);
+ expect(element.classes.contains('A')).toBe(false);
+ expect(element.classes.contains('B')).toBe(false);
+ });
});
}
diff --git a/test/directive/ng_cloak_spec.dart b/test/directive/ng_cloak_spec.dart
index bbf35d6c9..7781fb80c 100644
--- a/test/directive/ng_cloak_spec.dart
+++ b/test/directive/ng_cloak_spec.dart
@@ -45,5 +45,12 @@ main() {
expect(element.hasClass('ng-cloak')).toBe(false);
expect(element.hasClass('bar')).toBe(true);
});
+
+ it('should get removed when an element is compiled with data attribute', () {
+ var element = $('
');
+ expect(element.attr('data-ng-cloak')).toEqual('');
+ _.compile(element);
+ expect(element.attr('data-ng-cloak')).toBeNull();
+ });
});
}
diff --git a/test/directive/ng_events_spec.dart b/test/directive/ng_events_spec.dart
index 39cdfee35..9f220754f 100644
--- a/test/directive/ng_events_spec.dart
+++ b/test/directive/ng_events_spec.dart
@@ -20,6 +20,19 @@ void addTest(String name, [String eventType='MouseEvent', String eventName]) {
expect(_.rootScope.context['event'] is dom.UIEvent).toEqual(true);
}));
});
+
+ describe('data-ng-$name', () {
+ TestBed _;
+
+ beforeEach(inject((TestBed tb) => _ = tb));
+
+ it('should evaluate the expression on data-$name', inject(() {
+ _.compile(' ');
+ _.triggerEvent(_.rootElement, eventName, eventType);
+ expect(_.rootScope.context['abc']).toEqual(true);
+ expect(_.rootScope.context['event'] is dom.UIEvent).toEqual(true);
+ }));
+ });
}
main() {
diff --git a/test/directive/ng_if_spec.dart b/test/directive/ng_if_spec.dart
index ec2a92f51..a968c6710 100644
--- a/test/directive/ng_if_spec.dart
+++ b/test/directive/ng_if_spec.dart
@@ -222,4 +222,29 @@ main() {
expect(element.find('span').html()).toEqual('');
}
);
+
+ they('should add/remove the element with data attribute',
+ [ 'content
',
+ 'content
'],
+ (html) {
+ compile(html);
+ // The span node should NOT exist in the DOM.
+ expect(element.contents().length).toEqual(1);
+ expect(element.find('span').html()).toEqual('');
+
+ rootScope.apply(() {
+ rootScope.context['isVisible'] = true;
+ });
+
+ // The span node SHOULD exist in the DOM.
+ expect(element.contents().length).toEqual(2);
+ expect(element.find('span').html()).toEqual('content');
+
+ rootScope.apply(() {
+ rootScope.context['isVisible'] = false;
+ });
+
+ expect(element.find('span').html()).toEqual('');
+ }
+ );
}
diff --git a/test/directive/ng_include_spec.dart b/test/directive/ng_include_spec.dart
index 625821bdc..6dc6a30ee 100644
--- a/test/directive/ng_include_spec.dart
+++ b/test/directive/ng_include_spec.dart
@@ -42,5 +42,19 @@ main() {
expect(element.text).toEqual('I am Vojta');
})));
+ it('should fetch template from literal url with data attribute', async(inject((Scope scope, TemplateCache cache) {
+ cache.put('tpl.html', new HttpResponse(200, 'my name is {{name}}'));
+
+ var element = _.compile('
');
+
+ expect(element.innerHtml).toEqual('');
+
+ microLeap(); // load the template from cache.
+ scope.applyInZone(() {
+ scope.context['name'] = 'Vojta';
+ });
+ expect(element.text).toEqual('my name is Vojta');
+ })));
+
});
}
diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart
index f3634151e..2821fd678 100644
--- a/test/directive/ng_model_spec.dart
+++ b/test/directive/ng_model_spec.dart
@@ -109,6 +109,16 @@ describe('ng-model', () {
expect(element.selectionStart).toEqual(3);
expect(element.selectionEnd).toEqual(3);
}));
+
+ it('should update input value from model with data attribute', inject(() {
+ _.compile(' ');
+ _.rootScope.apply();
+
+ expect((_.rootElement as dom.InputElement).value).toEqual('');
+
+ _.rootScope.apply('model = "misko"');
+ expect((_.rootElement as dom.InputElement).value).toEqual('misko');
+ }));
});
/* This function simulates typing the given text into the input
diff --git a/test/directive/ng_model_validators_spec.dart b/test/directive/ng_model_validators_spec.dart
index d42e5fb5c..3ca47d8ef 100644
--- a/test/directive/ng_model_validators_spec.dart
+++ b/test/directive/ng_model_validators_spec.dart
@@ -70,6 +70,34 @@ describe('ngModel validators', () {
expect(model.valid).toEqual(true);
expect(model.invalid).toEqual(false);
}));
+
+ it('should validate the input field depending on if data-ng-required is true', inject((RootScope scope) {
+ _.compile(' ');
+ Probe probe = _.rootScope.context['i'];
+ var model = probe.directive(NgModel);
+
+ _.rootScope.apply();
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['requireMe'] = true;
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(false);
+ expect(model.invalid).toEqual(true);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['requireMe'] = false;
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+ }));
});
describe('[type="url"]', () {
@@ -203,6 +231,43 @@ describe('ngModel validators', () {
expect(model.invalid).toEqual(false);
}));
+ it('should validate the input field if a data-ng-pattern attribute is provided', inject((RootScope scope) {
+ _.compile(' ');
+ Probe probe = _.rootScope.context['i'];
+ var model = probe.directive(NgModel);
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "abc";
+ _.rootScope.context['myPattern'] = "[a-z]+";
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "abc";
+ _.rootScope.context['myPattern'] = "[0-9]+";
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(false);
+ expect(model.invalid).toEqual(true);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "123";
+ _.rootScope.context['myPattern'] = "123";
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+ }));
+
it('should validate the input field if a pattern attribute is provided', inject((RootScope scope) {
_.compile(' ');
Probe probe = _.rootScope.context['i'];
@@ -292,6 +357,34 @@ describe('ngModel validators', () {
expect(model.valid).toEqual(false);
expect(model.invalid).toEqual(true);
}));
+
+ it('should validate the input field if a data-ng-minlength attribute is provided', inject((RootScope scope) {
+ _.compile(' ');
+ Probe probe = _.rootScope.context['i'];
+ var model = probe.directive(NgModel);
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "abcdef";
+ _.rootScope.context['len'] = 3;
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "abc";
+ _.rootScope.context['len'] = 5;
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(false);
+ expect(model.invalid).toEqual(true);
+ }));
});
describe('maxlength', () {
@@ -348,5 +441,33 @@ describe('ngModel validators', () {
expect(model.valid).toEqual(false);
expect(model.invalid).toEqual(true);
}));
+
+ it('should validate the input field if a data-ng-maxlength attribute is provided', inject((RootScope scope) {
+ _.compile(' ');
+ Probe probe = _.rootScope.context['i'];
+ var model = probe.directive(NgModel);
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "abcdef";
+ _.rootScope.context['len'] = 6;
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(true);
+ expect(model.invalid).toEqual(false);
+
+ _.rootScope.apply(() {
+ _.rootScope.context['val'] = "abc";
+ _.rootScope.context['len'] = 1;
+ });
+
+ model.validate();
+ expect(model.valid).toEqual(false);
+ expect(model.invalid).toEqual(true);
+ }));
});
});
diff --git a/test/directive/ng_non_bindable_spec.dart b/test/directive/ng_non_bindable_spec.dart
index 867716c9d..e4223d362 100644
--- a/test/directive/ng_non_bindable_spec.dart
+++ b/test/directive/ng_non_bindable_spec.dart
@@ -35,5 +35,33 @@ main() {
// Bindings on the same node are processed.
expect(nonBindableDiv.attr('foo')).toEqual('one');
}));
+
+ it('should set ignore all other markup/directives on the descendent nodes with data attribute',
+ inject((Scope scope, Injector injector, Compiler compiler, DirectiveMap directives) {
+ var element = $('' +
+ '
{{a}} ' +
+ '
' +
+ '
' +
+ ' {{b}}' +
+ '
' +
+ '
{{a}} ' +
+ '
' +
+ '
');
+ compiler(element, directives)(injector, element);
+ scope.context['a'] = "one";
+ scope.context['b'] = "two";
+ scope.apply();
+ // Bindings not contained by data-ng-non-bindable should resolve.
+ expect(element.find("#s1").text().trim()).toEqual('one');
+ expect(element.find("#s2").text().trim()).toEqual('two');
+ expect(element.find("#s3").text().trim()).toEqual('one');
+ expect(element.find("#s4").text().trim()).toEqual('two');
+ // Bindings contained by data-ng-non-bindable should be left alone.
+ var nonBindableDiv = element.find("div");
+ expect(nonBindableDiv.html().trim()).toEqual(' {{b}}');
+ expect(nonBindableDiv.text().trim()).toEqual('{{b}}');
+ // Bindings on the same node are processed.
+ expect(nonBindableDiv.attr('foo')).toEqual('one');
+ }));
});
}
diff --git a/test/directive/ng_pluralize_spec.dart b/test/directive/ng_pluralize_spec.dart
index 951e1c80a..1a06e9f42 100644
--- a/test/directive/ng_pluralize_spec.dart
+++ b/test/directive/ng_pluralize_spec.dart
@@ -8,6 +8,7 @@ main() {
describe('deal with pluralized strings without offset', () {
var element;
var elementAlt;
+ var elementData;
var elt;
TestBed _;
@@ -31,6 +32,15 @@ main() {
"when-other='You have {} new emails'>" +
'
'
);
+
+ elementData = _.compile(
+ '" +
+ '
'
+ );
}));
it('should show single/plural strings', () {
@@ -38,51 +48,61 @@ main() {
_.rootScope.apply();
expect(element.text).toEqual('You have no new email');
expect(elementAlt.text).toEqual('You have no new email');
+ expect(elementData.text).toEqual('You have no new email');
_.rootScope.context['email'] = '0';
_.rootScope.apply();
expect(element.text).toEqual('You have no new email');
expect(elementAlt.text).toEqual('You have no new email');
+ expect(elementData.text).toEqual('You have no new email');
_.rootScope.context['email'] = 1;
_.rootScope.apply();
expect(element.text).toEqual('You have one new email');
expect(elementAlt.text).toEqual('You have one new email');
+ expect(elementData.text).toEqual('You have one new email');
_.rootScope.context['email'] = 0.01;
_.rootScope.apply();
expect(element.text).toEqual('You have 0.01 new emails');
expect(elementAlt.text).toEqual('You have 0.01 new emails');
+ expect(elementData.text).toEqual('You have 0.01 new emails');
_.rootScope.context['email'] = '0.1';
_.rootScope.apply();
expect(element.text).toEqual('You have 0.1 new emails');
expect(elementAlt.text).toEqual('You have 0.1 new emails');
+ expect(elementData.text).toEqual('You have 0.1 new emails');
_.rootScope.context['email'] = 2;
_.rootScope.apply();
expect(element.text).toEqual('You have 2 new emails');
expect(elementAlt.text).toEqual('You have 2 new emails');
+ expect(elementData.text).toEqual('You have 2 new emails');
_.rootScope.context['email'] = -0.1;
_.rootScope.apply();
expect(element.text).toEqual('You have -0.1 new emails');
expect(elementAlt.text).toEqual('You have -0.1 new emails');
+ expect(elementData.text).toEqual('You have -0.1 new emails');
_.rootScope.context['email'] = '-0.01';
_.rootScope.apply();
expect(element.text).toEqual('You have -0.01 new emails');
expect(elementAlt.text).toEqual('You have -0.01 new emails');
+ expect(elementData.text).toEqual('You have -0.01 new emails');
_.rootScope.context['email'] = -2;
_.rootScope.apply();
expect(element.text).toEqual('You have -2 new emails');
expect(elementAlt.text).toEqual('You have -2 new emails');
+ expect(elementData.text).toEqual('You have -2 new emails');
_.rootScope.context['email'] = -1;
_.rootScope.apply();
expect(element.text).toEqual('You have negative email. Whohoo!');
expect(elementAlt.text).toEqual('You have negative email. Whohoo!');
+ expect(elementData.text).toEqual('You have negative email. Whohoo!');
});
it('should show single/plural strings with mal-formed inputs', () {
@@ -90,41 +110,49 @@ main() {
_.rootScope.apply();
expect(element.text).toEqual('');
expect(elementAlt.text).toEqual('');
+ expect(elementData.text).toEqual('');
_.rootScope.context['email'] = null;
_.rootScope.apply();
expect(element.text).toEqual('');
expect(elementAlt.text).toEqual('');
+ expect(elementData.text).toEqual('');
_.rootScope.context['email'] = 'a3';
_.rootScope.apply();
expect(element.text).toEqual('');
expect(elementAlt.text).toEqual('');
+ expect(elementData.text).toEqual('');
_.rootScope.context['email'] = '011';
_.rootScope.apply();
expect(element.text).toEqual('You have 11 new emails');
expect(elementAlt.text).toEqual('You have 11 new emails');
+ expect(elementData.text).toEqual('You have 11 new emails');
_.rootScope.context['email'] = '-011';
_.rootScope.apply();
expect(element.text).toEqual('You have -11 new emails');
expect(elementAlt.text).toEqual('You have -11 new emails');
+ expect(elementData.text).toEqual('You have -11 new emails');
_.rootScope.context['email'] = '1fff';
_.rootScope.apply();
expect(element.text).toEqual('');
expect(elementAlt.text).toEqual('');
+ expect(elementData.text).toEqual('');
_.rootScope.context['email'] = '0aa22';
_.rootScope.apply();
expect(element.text).toEqual('');
expect(elementAlt.text).toEqual('');
+ expect(elementData.text).toEqual('');
_.rootScope.context['email'] = '000001';
_.rootScope.apply();
expect(element.text).toEqual('You have one new email');
expect(elementAlt.text).toEqual('You have one new email');
+ expect(elementData.text).toEqual('You have one new email');
});
});
diff --git a/test/directive/ng_repeat_spec.dart b/test/directive/ng_repeat_spec.dart
index eb0fa376c..d56a9f1cf 100644
--- a/test/directive/ng_repeat_spec.dart
+++ b/test/directive/ng_repeat_spec.dart
@@ -394,5 +394,14 @@ main() {
});
});
+ it(r'should set create a list of items with data attribute', inject((Scope scope, Compiler compiler, Injector injector) {
+ var element = $('');
+ BlockFactory blockFactory = compiler(element, directives);
+ Block block = blockFactory(injector, element);
+ scope.context['items'] = ['a', 'b'];
+ scope.apply();
+ expect(element.text()).toEqual('ab');
+ }));
+
});
}
diff --git a/test/directive/ng_show_hide_spec.dart b/test/directive/ng_show_hide_spec.dart
index c0c01d66f..9498a0eff 100644
--- a/test/directive/ng_show_hide_spec.dart
+++ b/test/directive/ng_show_hide_spec.dart
@@ -23,6 +23,22 @@ main() {
});
expect(_.rootElement).not.toHaveClass('ng-hide');
});
+
+ it('should add/remove ng-hide class with data attribute', () {
+ _.compile('
');
+
+ expect(_.rootElement).not.toHaveClass('ng-hide');
+
+ _.rootScope.apply(() {
+ _.rootScope.context['isHidden'] = true;
+ });
+ expect(_.rootElement).toHaveClass('ng-hide');
+
+ _.rootScope.apply(() {
+ _.rootScope.context['isHidden'] = false;
+ });
+ expect(_.rootElement).not.toHaveClass('ng-hide');
+ });
});
describe('NgShow', () {
@@ -44,5 +60,21 @@ main() {
});
expect(_.rootElement).toHaveClass('ng-hide');
});
+
+ it('should add/remove ng-hide class with data attribute', () {
+ _.compile('
');
+
+ expect(_.rootElement).not.toHaveClass('ng-hide');
+
+ _.rootScope.apply(() {
+ _.rootScope.context['isShown'] = true;
+ });
+ expect(_.rootElement).not.toHaveClass('ng-hide');
+
+ _.rootScope.apply(() {
+ _.rootScope.context['isShown'] = false;
+ });
+ expect(_.rootElement).toHaveClass('ng-hide');
+ });
});
}
diff --git a/test/directive/ng_src_boolean_spec.dart b/test/directive/ng_src_boolean_spec.dart
index e9a8a1795..2f3556f67 100644
--- a/test/directive/ng_src_boolean_spec.dart
+++ b/test/directive/ng_src_boolean_spec.dart
@@ -245,5 +245,11 @@ main() {
_.rootScope.apply();
expect(_.rootElement.attributes['quack']).toEqual('vanilla');
}));
+
+ it('should bind * even if no interpolation with data attribute', inject(() {
+ _.compile(' ');
+ _.rootScope.apply();
+ expect(_.rootElement.attributes['quack']).toEqual('vanilla');
+ }));
});
}
diff --git a/test/directive/ng_style_spec.dart b/test/directive/ng_style_spec.dart
index 8406a14cc..4ac204cce 100644
--- a/test/directive/ng_style_spec.dart
+++ b/test/directive/ng_style_spec.dart
@@ -14,6 +14,12 @@ main() => describe('NgStyle', () {
expect(element.style.height).toEqual('40px');
});
+ it('should set with data attribute', () {
+ dom.Element element = _.compile('
');
+ _.rootScope.apply();
+ expect(element.style.height).toEqual('40px');
+ });
+
it('should silently ignore undefined style', () {
dom.Element element = _.compile('
');
diff --git a/test/directive/ng_switch_spec.dart b/test/directive/ng_switch_spec.dart
index 55f0c70ff..b1fff72b2 100644
--- a/test/directive/ng_switch_spec.dart
+++ b/test/directive/ng_switch_spec.dart
@@ -200,4 +200,30 @@ main() => describe('ngSwitch', () {
expect(child2).toBeDefined();
expect(child2).not.toBe(child1);
}));
+
+ it('should switch on value change with data attribute', inject(() {
+ var element = _.compile(
+ '' +
+ '
first:{{name}}
' +
+ '
second:{{name}}
' +
+ '
true:{{name}}
' +
+ '
');
+ expect(element.innerHtml).toEqual(
+ '');
+ _.rootScope.context['select'] = 1;
+ _.rootScope.apply();
+ expect(element.text).toEqual('first:');
+ _.rootScope.context['name'] = "shyam";
+ _.rootScope.apply();
+ expect(element.text).toEqual('first:shyam');
+ _.rootScope.context['select'] = 2;
+ _.rootScope.apply();
+ expect(element.text).toEqual('second:shyam');
+ _.rootScope.context['name'] = 'misko';
+ _.rootScope.apply();
+ expect(element.text).toEqual('second:misko');
+ _.rootScope.context['select'] = true;
+ _.rootScope.apply();
+ expect(element.text).toEqual('true:misko');
+ }));
});