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.