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/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
index 5d09edde3..61e4c3ef6 100644
--- a/test/utils_spec.dart
+++ b/test/utils_spec.dart
@@ -31,5 +31,19 @@ main() {
}).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');
+ });
+ });
}