From da2a17f80df9b211bbaabb23160e506aaf1ede06 Mon Sep 17 00:00:00 2001 From: Avital Oliver Date: Tue, 14 Jan 2014 19:29:55 -0800 Subject: [PATCH] Use custom attribute handler for 'value' and 'checked'. Setting these attribute on DOM elements only affects their initial state. Instead, one should set the JavaScript property on the DOM element directly. Fixes #1752 --- packages/ui/attrs.js | 14 ++++++++++---- packages/ui/render_tests.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/packages/ui/attrs.js b/packages/ui/attrs.js index 01be4cee70..af25cd1667 100644 --- a/packages/ui/attrs.js +++ b/packages/ui/attrs.js @@ -121,19 +121,25 @@ var isSVGElement = function (elem) { // XXX make it possible for users to register attribute handlers! makeAttributeHandler = function (elem, name, value) { - // XXX will need one for 'style' on IE, though modern browsers - // seem to handle setAttribute ok. + // generally, use setAttribute but certain attributes need to be set + // by directly setting a JavaScript property on the DOM element. if (name === 'class') { if (isSVGElement(elem)) { return new SVGClassHandler(name, value); } else { return new ClassHandler(name, value); } - } else if (name === 'selected') { + } else if (name === 'selected' || name === 'checked') { return new BooleanHandler(name, value); - } else if (elem.tagName === 'TEXTAREA' && name === 'value') { + } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT') + && name === 'value') { + // internally, TEXTAREAs tracks their value in the 'value' + // attribute just like INPUTs. return new ValueHandler(name, value); } else { return new AttributeHandler(name, value); } + + // XXX will need one for 'style' on IE, though modern browsers + // seem to handle setAttribute ok. }; diff --git a/packages/ui/render_tests.js b/packages/ui/render_tests.js index 1622763135..9663cfc97f 100644 --- a/packages/ui/render_tests.js +++ b/packages/ui/render_tests.js @@ -13,6 +13,7 @@ var LI = HTML.LI; var SPAN = HTML.SPAN; var HR = HTML.HR; var TEXTAREA = HTML.TEXTAREA; +var INPUT = HTML.INPUT; Tinytest.add("ui - render - basic", function (test) { var run = function (input, expectedInnerHTML, expectedHTML, expectedCode) { @@ -74,6 +75,39 @@ Tinytest.add("ui - render - basic", function (test) { }); +// test that we correctly update the 'value' property on input fields +// rather than the 'value' attribute. the 'value' attribute only sets +// the initial value. +Tinytest.add("ui - render - input - value", function (test) { + var R = ReactiveVar("hello"); + var div = document.createElement("DIV"); + materialize(INPUT({value: function () { return R.get(); }}), div); + var inputEl = div.querySelector('input'); + test.equal(inputEl.value, "hello"); + inputEl.value = "goodbye"; + R.set("hola"); + Deps.flush(); + test.equal(inputEl.value, "hola"); +}); + +// test that we correctly update the 'checked' property rather than +// the 'checked' attribute on input fields of type 'checkbox'. the +// 'checked' attribute only sets the initial value. +Tinytest.add("ui - render - input - checked", function (test) { + var R = ReactiveVar(null); + var div = document.createElement("DIV"); + materialize(INPUT({type: "checkbox", checked: function () { return R.get(); }}), div); + var inputEl = div.querySelector('input'); + test.equal(inputEl.checked, false); + inputEl.checked = true; + + R.set("checked"); + Deps.flush(); + R.set(null); + Deps.flush(); + test.equal(inputEl.checked, false); +}); + Tinytest.add("ui - render - textarea", function (test) { var run = function (optNode, text, html, code) { if (typeof optNode === 'string') {