on master help sign in
Fix a bug where "volatile" attributes weren't getting properly updated
commit5837d538efabe43a21a9799f06b7e48a8d6ae181 authorNick Fitzgerald <fitzgen@gmail.com> dateMon 11 Feb 2019, 18:27 (8 years ago) parent25dcb1c
3 files changed+55−10
js/change-list.js+28−2 src/node.rs+14 src/vdom.rs+13−8
js/change-list.js+28−2
@@ -49,7 +49,20 @@ const OP_TABLE = [
4949 const pointer2 = mem32[i++];
5050 const length2 = mem32[i++];
5151 const value = string(mem8, pointer2, length2);
52− top(changeList.stack).setAttribute(name, value);
52+ const node = top(changeList.stack);
53+ node.setAttribute(name, value);
54+
55+ // Some attributes are "volatile" and don't work through `setAttribute`.
56+ if (name === "value") {
57+ node.value = value;
58+ }
59+ if (name === "checked") {
60+ node.checked = true;
61+ }
62+ if (name === "selected") {
63+ node.selected = true;
64+ }
65+
5366 return i;
5467 },
5568
@@ -58,7 +71,20 @@ const OP_TABLE = [
5871 const pointer = mem32[i++];
5972 const length = mem32[i++];
6073 const name = string(mem8, pointer, length);
61− top(changeList.stack).removeAttribute(name);
74+ const node = top(changeList.stack);
75+ node.removeAttribute(name);
76+
77+ // Some attributes are "volatile" and don't work through `removeAttribute`.
78+ if (name === "value") {
79+ node.value = null;
80+ }
81+ if (name === "checked") {
82+ node.checked = false;
83+ }
84+ if (name === "selected") {
85+ node.selected = false;
86+ }
87+
6288 return i;
6389 },
6490
src/node.rs+14
@@ -70,6 +70,20 @@ impl fmt::Debug for Listener<'_> {
7070 }
7171}
7272
73+impl<'a> Attribute<'a> {
74+ /// Certain attributes are considered "volatile" and can change via user
75+ /// input that we can't see when diffing against the old virtual DOM. For
76+ /// these attributes, we want to always re-set the attribute on the physical
77+ /// DOM node, even if the old and new virtual DOM nodes have the same value.
78+ #[inline]
79+ pub(crate) fn is_volatile(&self) -> bool {
80+ match self.name {
81+ "value" | "checked" | "selected" => true,
82+ _ => false,
83+ }
84+ }
85+}
86+
7387impl<'a> Node<'a> {
7488 /// Construct a new element node with the given tag name and children.
7589 #[inline]
src/vdom.rs+13−8
@@ -364,17 +364,22 @@ impl VdomInnerExclusive {
364364 // Do O(n^2) passes to add/update and remove attributes, since
365365 // there are almost always very few attributes.
366366 'outer: for new_attr in new {
367− for old_attr in old {
368− if old_attr.name == new_attr.name {
369− if old_attr.value != new_attr.value {
370− self.change_list
371− .emit_set_attribute(new_attr.name, new_attr.value);
367+ if new_attr.is_volatile() {
368+ self.change_list
369+ .emit_set_attribute(new_attr.name, new_attr.value);
370+ } else {
371+ for old_attr in old {
372+ if old_attr.name == new_attr.name {
373+ if old_attr.value != new_attr.value {
374+ self.change_list
375+ .emit_set_attribute(new_attr.name, new_attr.value);
376+ }
377+ continue 'outer;
372378 }
373− continue 'outer;
374379 }
380+ self.change_list
381+ .emit_set_attribute(new_attr.name, new_attr.value);
375382 }
376− self.change_list
377− .emit_set_attribute(new_attr.name, new_attr.value);
378383 }
379384
380385 'outer2: for old_attr in old {