{
const main = () => {
document.querySelectorAll(".Counter").forEach(element => {
render({element: element, state: {value: 0}})
})
}
const render = ({element, state}) => {
console.debug(`Rendering`, state, `into`, element)
// First, we select the old root element.
// If this is the first time we're rendering, we'll need to create it.
let old_root = element.querySelector("#root")
if (!old_root) {
old_root = document.createElement('div')
element.appendChild(old_root)
}
// Next, we generate a *new* root element from scratch.
// We're going to configure this element to reflect our state.
const new_root = document.createElement('div')
new_root.id = "root"
// This sets up the new root element but does *not* attach any handlers.
const {value} = state // This uses ES6 destructuring to get `value` from state.
new_root.innerHTML = `
<span id="current_value">${value}</span>
<button id="increment">Increment</button>
<button id="reset">Reset</button>`
/* Note this uses ES6 template syntax--if value is 3,
`abc${value}def` becomes `abc3def`. */
// Now that the interface exists, we can attach event handlers.
// When we click the increment button, we want to modify part
// of the state by increasing `value` by 1.
new_root.querySelector('#increment').onclick =
() => update_state({value: value+1}) // See the definition of update_state below.
// When we click the reset button, we want to set `value` to 0.
new_root.querySelector('#reset').onclick =
() => update_state({value: 0})
// This is how we update the state.
const update_state = update_object => {
console.debug(`Updating`, state, `with a partial state`, update_object,
`and rerendering (after yielding execution).`)
// It doesn't matter here, but if we're handling "continuous" input
// (i.e. from a mouse), we have to yield execution with setTimeout so
// the browser can continue capturing events.
setTimeout(render({element: element, state: {...state, ...update_object}}))
}
// Now that the new root element has been created, we replace
// the old root element with the new root element.
old_root.parentElement.replaceChild(new_root, old_root)
}
main() // (Runs the main function.)
page // (Ignore this.) Tells Observable this cell should rerun if the `page` cell changes.
return "Read this!"
}