Thanks @bgchen !
As you say the @jashkenas/input
library wraps each control in a <form>
element; aka “wrapper element”.
A few interesting notes:
These produce the same thing. I thought the parentheses may cause viewof
to apply to different values. But these all produce the same result; the HTMLInputElement
of the <input type="text">
named input
viewof library_input.input
(viewof library_input).input
(viewof library_input.input)
But now I’m thinking viewof
applies to the values to its right, even before the dot operator (higher precedence). Maybe that’s why viewof
doesn’t like parentheses to its right. Maybe viewof
has highest precedence; must evaluate first. Which might explain why the above parentheses change doesn’t make a difference, and these parentheses cause error:
viewof (library_input.input)
SyntaxError: Unexpected token
Even if we access the input(s) inside each form, it may not work. I think this is a general challenge with HTML elements. For example in plain HTML/DOM APIs, changing a <input type="text">
is as simple as setting the value
attribute, and getting the attribute again:
document.querySelector('[name=library_input]').value= 'new library input'
document.querySelector('[name=library_input]').value
However, other controls like <select multiple>
or <input type="checkbox">
are not so easy to get/set.
For example, setting <input type="checkbox">
requires adding the checked
attribute and/or setting the checked
property.
Likewise, getting the value of a <select multiple>
is not as easy as reading a single value
attribute. Instead each child option
element must be checked
While @jashkenas/input
supports getValue
to convert HTML state to a value but there is no concept of setValue
. (Here’s how @jashkenas/inputs
getValue of a <select multiple>
)
getValue: input => {
const selected = Array.prototype.filter
.call(input.options, i => i.selected)
.map(i => options[+i.value].value);
return multiple ? selected : selected[0];
},
The @jashkenas/inputs
strategy of wrapping input(s) in a container like a <form>
is also used in linked inputs and multi-value inputs***. I cannot set the value in either of those notebook either; this doesn’t work in the multi-value input notebook:
viewof rgb.value = [ 120, 100, 90 ]
So the concept of setValue
is a common challenge. One solution is to use the “more general approach … a minimal view”. The set
is supported as part of the EventTarget interface
provided in the View
class: import {View} from "@mbostock/synchronized-views"
set value(value) {
this._value = value;
this.dispatchEvent({type: "input", value});
}
But then you must bind
your view to your input(s):
- addEventListener to react : when the View (EventTarget) changes -> update your input
- listen to your input to react: when user changes the input -> update the View
Note about the “wrapper element” as I call it:
All three cases assign the property value
to the wrapper element so the viewof
operator can get what it needs.