From d72755a20af3b0cb7d79d77599b4029834b51cad Mon Sep 17 00:00:00 2001 From: Rafael Weinstein Date: Tue, 26 Nov 2013 16:25:12 -0800 Subject: [PATCH] Allow binding to computed properties R=arv BUG= Review URL: https://codereview.appspot.com/33500043 --- src/polymer-expressions.js | 52 ++++++++++++++++++++++++--------- tests/tests.js | 60 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/src/polymer-expressions.js b/src/polymer-expressions.js index fa6280c..214bfae 100644 --- a/src/polymer-expressions.js +++ b/src/polymer-expressions.js @@ -127,6 +127,27 @@ } }; + function MemberExpression(object, property) { + this.object = object; + this.property = property; + } + + MemberExpression.prototype = { + valueFn: function() { + var object = this.object; + var property = this.property; + return function(values) { + return object(values)[property(values)]; + }; + }, + + setValue: function(object, newValue, depsValues) { + object = this.object(depsValues); + var property = this.property(depsValues); + return object[property] = newValue; + } + }; + function Filter(name, args) { this.name = name; this.args = args; @@ -189,7 +210,7 @@ }; function getFn(arg) { - return arg instanceof IdentPath ? arg.valueFn() : arg; + return typeof arg == 'function' ? arg : arg.valueFn(); } function ASTDelegate() { @@ -208,7 +229,8 @@ createLabeledStatement: function(label, expression) { this.labeledStatements.push({ label: label, - expression: expression instanceof IdentPath ? expression.valueFn() : expression + expression: typeof expression == 'function' ? expression + : expression.valueFn() }); return expression; }, @@ -253,14 +275,9 @@ }, createMemberExpression: function(accessor, object, property) { - if (accessor === '[') { - object = getFn(object); - property = getFn(property); - return function(values) { - return object(values)[property(values)]; - }; - } - return new IdentPath(this, property.name, object); + return accessor === '[' ? + new MemberExpression(getFn(object), getFn(property)) : + new IdentPath(this, property.name, object); }, createLiteral: function(token) { @@ -354,7 +371,16 @@ var self = this; var setValueFn = function(newValue) { - self.setValue(model, newValue); + var values; + if (self.paths.length == 1) { + values = self.paths[0].getValueFrom(model); + } else { + values = []; + for (var i = 0; i < self.paths.length; i++) + values[i] = self.paths[i].getValueFrom(model); + } + + self.setValue(model, newValue, values); }; if (paths.length === 1) { @@ -375,14 +401,14 @@ return binding; }, - setValue: function(model, newValue) { + setValue: function(model, newValue, depsValues) { var count = this.filters ? this.filters.length : 0; while (count-- > 0) { newValue = this.filters[count].toModel(newValue); } if (this.expression.setValue) - return this.expression.setValue(model, newValue); + return this.expression.setValue(model, newValue, depsValues); } } diff --git a/tests/tests.js b/tests/tests.js index babd599..061de06 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -736,6 +736,66 @@ suite('PolymerExpressions', function() { assert.equal('F', div.childNodes[1].textContent); }); + test('two-way computed property', function() { + var div = createTestHtml( + ''); + + var model = { + bar: { + 'contains space': 'a' + } + }; + + recursivelySetTemplateModel(div, model); + Platform.performMicrotaskCheckpoint(); + assert.equal('a', div.childNodes[1].value); + + div.childNodes[1].value = 'b'; + dispatchEvent('input', div.childNodes[1]); + + Platform.performMicrotaskCheckpoint(); + assert.equal('b', model.bar['contains space']); + }); + + test('dynamic two-way computed property', function() { + var div = createTestHtml( + ''); + + var model = { + foo: { + a: '1', + b: '3' + }, + bar: 'a' + }; + + recursivelySetTemplateModel(div, model); + Platform.performMicrotaskCheckpoint(); + assert.equal('1', div.childNodes[1].value); + + div.childNodes[1].value = '2'; + dispatchEvent('input', div.childNodes[1]); + + Platform.performMicrotaskCheckpoint(); + assert.equal('2', model.foo.a); + assert.equal('3', model.foo.b); + + model.bar = 'b'; + Platform.performMicrotaskCheckpoint(); + assert.equal('3', div.childNodes[1].value); + + div.childNodes[1].value = '4'; + dispatchEvent('input', div.childNodes[1]); + + Platform.performMicrotaskCheckpoint(); + assert.equal('2', model.foo.a); + assert.equal('4', model.foo.b); + }); + test('two-way filter', function() { PolymerExpressions.filters.hex = hex;