diff --git a/index.js b/index.js index 0ca7bf8..02fce62 100644 --- a/index.js +++ b/index.js @@ -518,6 +518,19 @@ DynamicAttribute.prototype.update = function(context, binding) { var element = binding.element; var propertyName = !this.elementNs && UPDATE_PROPERTIES[binding.name]; if (propertyName) { + // Update via DOM property, short-circuiting if no update is needed. + // Certain properties must be strings, so for those properties, the value gets stringified. + // + // There is one special case, when updating the string `input.value` property with a number. + // If a user tries to type "1.01" in an `, then once they've typed "1.0", + // the context value is set to `1`, triggering this update function to set the input value to + // "1". That means typing "1.01" would be impossible without special handling to avoid + // overwriting an existing input value of "1.0" with a new value of "1". + if (element.tagName === 'INPUT' && propertyName === 'value' && typeof value === 'number') { + if (parseFloat(element.value) === value) { + return; + } + } var propertyValue = (STRING_PROPERTIES[binding.name]) ? this.stringify(value) : value; if (element[propertyName] === propertyValue) return; diff --git a/test/test.mocha.js b/test/test.mocha.js index e0218eb..361d982 100644 --- a/test/test.mocha.js +++ b/test/test.mocha.js @@ -717,6 +717,25 @@ function testBindingUpdates(render) { expect(input.value).equal(''); }); + it('does not clobber input type="number" value when typing "1.0"', function() { + var template = new saddle.Template([ + new saddle.Element('input', { + 'type': new saddle.Attribute('number'), + 'value': new saddle.DynamicAttribute(new expressions.Expression('amount')), + }) + ]); + + var binding = render(template).pop(); + var input = fixture.firstChild; + + // Make sure that a user-typed input value of "1.0" does not get clobbered by + // a context value of `1`. + input.value = '1.0'; + binding.context = getContext({amount: 1}); + binding.update(); + expect(input.value).equal('1.0'); + }); + it('updates "title" attribute', function() { var template = new saddle.Template([ new saddle.Element('div', {