diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart
index 756ff889d..6e69b78e9 100644
--- a/lib/core_dom/element_binder.dart
+++ b/lib/core_dom/element_binder.dart
@@ -308,6 +308,7 @@ class ElementBinder {
var jsNode;
List bindAssignableProps = [];
bindAttrs.forEach((String prop, AST ast) {
+ prop = camelCase(prop);
if (jsNode == null) jsNode = new js.JsObject.fromBrowserObject(node);
scope.watchAST(ast, (v, _) {
jsNode[prop] = v;
diff --git a/lib/utils.dart b/lib/utils.dart
index dbaa06ac3..135293cc0 100644
--- a/lib/utils.dart
+++ b/lib/utils.dart
@@ -81,6 +81,12 @@ relaxFnArgs(Function fn) {
capitalize(String s) => s.substring(0, 1).toUpperCase() + s.substring(1);
+String camelCase(String s) {
+ var part = s.split('-').map((s) => s.toLowerCase());
+ if (part.length <= 1)
+ return part.join();
+ return part.first + part.skip(1).map(capitalize).join();
+}
/// Returns whether or not the given identifier is a reserved word in Dart.
bool isReservedWord(String identifier) => RESERVED_WORDS.contains(identifier);
diff --git a/test/angular_spec.dart b/test/angular_spec.dart
index 5b6d4e5de..bd84d6dec 100644
--- a/test/angular_spec.dart
+++ b/test/angular_spec.dart
@@ -3,7 +3,6 @@ library angular_spec;
import 'dart:mirrors';
import '_specs.dart';
-import 'package:angular/utils.dart';
import 'package:angular/tools/symbol_inspector/symbol_inspector.dart';
main() {
@@ -16,34 +15,6 @@ main() {
});
});
- describe('relaxFnApply', () {
- it('should work with 6 arguments', () {
- var sixArgs = [1, 1, 2, 3, 5, 8];
- expect(relaxFnApply(() => "none", sixArgs)).toEqual("none");
- expect(relaxFnApply((a) => a, sixArgs)).toEqual(1);
- expect(relaxFnApply((a, b) => a + b, sixArgs)).toEqual(2);
- expect(relaxFnApply((a, b, c) => a + b + c, sixArgs)).toEqual(4);
- expect(relaxFnApply((a, b, c, d) => a + b + c + d, sixArgs)).toEqual(7);
- expect(relaxFnApply((a, b, c, d, e) => a + b + c + d + e, sixArgs)).toEqual(12);
- });
-
- it('should work with 0 arguments', () {
- var noArgs = [];
- expect(relaxFnApply(() => "none", noArgs)).toEqual("none");
- expect(relaxFnApply(([a]) => a, noArgs)).toEqual(null);
- expect(relaxFnApply(([a, b]) => b, noArgs)).toEqual(null);
- expect(relaxFnApply(([a, b, c]) => c, noArgs)).toEqual(null);
- expect(relaxFnApply(([a, b, c, d]) => d, noArgs)).toEqual(null);
- expect(relaxFnApply(([a, b, c, d, e]) => e, noArgs)).toEqual(null);
- });
-
- it('should fail with not enough arguments', () {
- expect(() {
- relaxFnApply((required, alsoRequired) => "happy", [1]);
- }).toThrowWith(message: 'Unknown function type, expecting 0 to 5 args.');
- });
- });
-
describe('symbols', () {
it('should not export unknown symbols from animate', () {
LibraryInfo libraryInfo;
diff --git a/test/core_dom/web_components_spec.dart b/test/core_dom/web_components_spec.dart
index bdb68278a..7ad9f7198 100644
--- a/test/core_dom/web_components_spec.dart
+++ b/test/core_dom/web_components_spec.dart
@@ -58,29 +58,36 @@ main() {
it('should bind to Custom Element properties', () {
- registerElement('tests-bound', {'prop-y': 10});
+ registerElement('tests-bound', {'propY': 10});
compileAndUpgrade('');
// Scope has not been digested yet
- expect(customProp('prop-y')).toEqual(10);
+ expect(customProp('propY')).toEqual(10);
_.rootScope.apply();
- expect(customProp('prop-y')).toEqual(27);
+ expect(customProp('propY')).toEqual(27);
});
it('should bind to a non-existent property', () {
registerElement('tests-empty', {});
- compileAndUpgrade('');
+ compileAndUpgrade('');
_.rootScope.apply();
- expect(customProp('new-prop')).toEqual(27);
+ expect(customProp('newprop')).toEqual(27);
+ });
+
+ it('should bind to a camelCase property', () {
+ registerElement('tests-camel', {});
+ compileAndUpgrade('');
+ _.rootScope.apply();
+ expect(customProp('newProp')).toEqual(27);
});
it('should bind to both directives and properties', () {
registerElement('tests-double', {});
compileAndUpgrade('');
_.rootScope.apply();
- expect(customProp('ng-bind')).toEqual("hello");
+ expect(customProp('ngBind')).toEqual("hello");
expect(_.rootElement).toHaveText('hello');
});
diff --git a/test/utils_spec.dart b/test/utils_spec.dart
new file mode 100644
index 000000000..61e4c3ef6
--- /dev/null
+++ b/test/utils_spec.dart
@@ -0,0 +1,49 @@
+library utils_spec;
+
+import '_specs.dart';
+import 'package:angular/utils.dart';
+
+main() {
+ describe('relaxFnApply', () {
+ it('should work with 6 arguments', () {
+ var sixArgs = [1, 1, 2, 3, 5, 8];
+ expect(relaxFnApply(() => "none", sixArgs)).toEqual("none");
+ expect(relaxFnApply((a) => a, sixArgs)).toEqual(1);
+ expect(relaxFnApply((a, b) => a + b, sixArgs)).toEqual(2);
+ expect(relaxFnApply((a, b, c) => a + b + c, sixArgs)).toEqual(4);
+ expect(relaxFnApply((a, b, c, d) => a + b + c + d, sixArgs)).toEqual(7);
+ expect(relaxFnApply((a, b, c, d, e) => a + b + c + d + e, sixArgs)).toEqual(12);
+ });
+
+ it('should work with 0 arguments', () {
+ var noArgs = [];
+ expect(relaxFnApply(() => "none", noArgs)).toEqual("none");
+ expect(relaxFnApply(([a]) => a, noArgs)).toEqual(null);
+ expect(relaxFnApply(([a, b]) => b, noArgs)).toEqual(null);
+ expect(relaxFnApply(([a, b, c]) => c, noArgs)).toEqual(null);
+ expect(relaxFnApply(([a, b, c, d]) => d, noArgs)).toEqual(null);
+ expect(relaxFnApply(([a, b, c, d, e]) => e, noArgs)).toEqual(null);
+ });
+
+ it('should fail with not enough arguments', () {
+ expect(() {
+ relaxFnApply((required, alsoRequired) => "happy", [1]);
+ }).toThrowWith(message: 'Unknown function type, expecting 0 to 5 args.');
+ });
+ });
+
+ describe('camelCase', () {
+ it('should ignore non camelCase', () {
+ expect(camelCase('regular')).toEqual('regular');
+ });
+
+ it('should convert snake-case', () {
+ expect(camelCase('snake-case')).toEqual('snakeCase');
+ });
+
+ it('should lowercase strings', () {
+ expect(camelCase('Caps-first')).toEqual('capsFirst');
+ });
+ });
+}
+