To understand why undefined
isn’t good enough, we’ll create a simple test case, a notebook with a single viewof
cell:
viewof hello = html`<div>`
Let’s take a look at the generated code:
- Enable link sharing.
- Open up the cell’s Embed code dialog.
- Look for the script URL after
import define from
and copy it.
- Open the script URL in your browser.
You should see something like this:
// https://observablehq.com/d/0123456789abcdef@1
export default function define(runtime, observer) {
const main = runtime.module();
main.variable(observer("viewof hello")).define("viewof hello", ["html"], function(html){return(
html`<div>`
)});
main.variable(observer("hello")).define("hello", ["Generators", "viewof hello"], (G, _) => G.input(_));
return main;
}
Observable wraps each cell inside a so-called Variable
instance. Looking through the code, we see our hello
cell defined. Actually, we see it defined twice:
viewof hello
: The “original” cell, containing our <div>
DOM element,
hello
: This is the value of our viewof
cell that gets passed to other cells.
In the second define()
we can rename the arguments G
and _
to end up with a cell that reads:
Generators.input(viewof hello)
If you had looked at Observable’s Standard Library before, then Generators.input()
might look familiar. Its documentation even tells us:
Generators.input is used by Observable’s viewof operator to define the current value of a view […] it can be used to define a generator cell exposing the current value of an input […].
And right at the top of the function’s documentation, we find our answer:
[…] If the initial value of the input is not undefined, the returned generator’s first yielded value is a resolved promise with the initial value of the input .
By passing undefined
, we end up with a Generator that won’t yield until the next input
event.
Going back to Jeremy’s Inputs library, and more specifically radio()
, we need to understand the following:
radio()
won’t blindly set value
to whatever we pass in our widget configuration. Instead it will mark any of the radio inputs as checked
if its value matches.
radio()
relies on input()
for some of its functionality. Instead of settings the value directly, radio()
passes a getValue()
callback along.
- This
getValue()
callback will go through the widget’s radio inputs to look for the first one that’s checked
, and return its value. If none is checked, it will return undefined
.
input()
will gladly take whatever value the callback returns, and set it as the cell’s value.
So there you have it, a much too elaborate (but hopefully insightful) explanation for why you need to apply value
after instantiating the widget, and why undefined
needs to be wrapped. If you feel that I’ve omitted details or that some aspects could be made clearer, please let me know, and I’ll gladly update the post.