Published
Edited
May 12, 2020
Fork of Form Input
Importers
2 stars
Insert cell
Insert cell
Insert cell
viewof formOutput = form(
html`<form>
<div>Change the inputs and see the value change below. Note the extra field from the transform.</div>
<div>
<input type="text" name="message" value="Hi"> message
</div>
<div>
<input type="range" name="slider" min=0 max=100 value="33"> slider
</div>
</form>`,
{ transform: val => ({ ...val, added: val.slider * 2 }) }
)
Insert cell
formOutput
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
state
Insert cell
Insert cell
viewof state = new View({ message: "Initial message", hue: 180, size: 24 })
Insert cell
md`---
## *bindContainer() example*

\`// TODO: This section\`
`
Insert cell
Insert cell
// TODO: Consider adding an inverse option that lets you invert the transformation
// TODO: Add a hook into validation somewhere, perhaps in transform if it is also passed the old value
// but then needs some mechanism to reject the change
// TODO: Consider rewriting the view class as a missing property Proxy
form = function(formHtml, opts) {
const { trigger, transform } = { trigger: triggers.input, ...opts };
const container = html`<div>${formHtml}`;

// Set up the container object by adding the form and correct triggers
container.form = formHtml;
trigger(container);

// Function to call to pull a value from the input fields when the container's input event is triggered
container.setValue = () => container.value = transform
? transform(getFormValue(formHtml))
: getFormValue(formHtml);

// Function to push a value into the input fields when it is updated from a binding (or manually)
container.renderValue = value => setFormValue(formHtml, container.value);

// Pull the initial value and return
container.setValue();
return container;
}
Insert cell
Insert cell
Insert cell
Insert cell
boundForm = function(view, formHtml, opts) {
return bindContainer(view, form(formHtml, opts));
}
Insert cell
// TODO: Can this be generalized to work with any value, not just objects (forms will still require objects)?
function bindContainer(view, container) {
// Define bi-directional event handlers
// The view updater is fired without details and sets the view's value to the current container value
// The container updater is then fired each time the view is set (including above), and is called with the state in details
const updateView = () => view.value = { ...view.value, ... container.value }
const updateContainer = () => {
container.value = { ...container.value, ...view.value }
// If the container requires its display to be updated, it should provide a renderValue method
if (typeof container.renderValue === 'function') container.renderValue(container.value)
}
// Attach the event handlers
container.addEventListener('input', updateView)
view.addEventListener('input', updateContainer)
// When first loading, pull the initial value from the state
updateContainer(new CustomEvent('input', { detail: { ...view.value } }));
// Destroy the event handlers when disposed
// Probably does not require explicitly destroying the one the container
return Generators.disposable(container, () => {
view.removeEventListener('input', updateContainer)
container.removeEventListener('input', updateView)
});
}
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more