Skip to content
This repository was archived by the owner on Mar 2, 2021. It is now read-only.

Commit 5837d53

Browse files
committed
Fix a bug where "volatile" attributes weren't getting properly updated
1 parent 25dcb1c commit 5837d53

File tree

3 files changed

+55
-10
lines changed

3 files changed

+55
-10
lines changed

js/change-list.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
7387
impl<'a> Node<'a> {
7488
/// Construct a new element node with the given tag name and children.
7589
#[inline]

src/vdom.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {

0 commit comments

Comments
 (0)