Published
Edited
Jan 10, 2021
1 fork
11 stars
Insert cell
Insert cell
todos
Insert cell
viewof todos = {
const root = html`<div>`;
let todos;

// Inserts a new todo before the specified index.
function addTodo(i = todos.length) {
const newTodos = todos.slice();
newTodos.splice(i, 0, "");
setTodos(newTodos);
root.children[i].querySelector("input").focus();
}

// Modifies the todo at the given index to have the given value.
function modifyTodo(i, value) {
const newTodos = todos.slice();
newTodos[i] = value;
setTodos(newTodos);
}

// Removes the todo at the given index, focusing the todo before.
function removeTodo(i) {
const newTodos = todos.slice();
newTodos.splice(i, 1);
setTodos(newTodos);
root.children[i - 1].querySelector("input").focus();
}

// Renders the view, like a React useState hook.
function setTodos(newTodos) {
todos = newTodos.map(t => t.toUpperCase());
morph(root, html`<div>
${todos.map((todo, i) => html`<div>
${html`<input value=${todo}
oninput=${event => modifyTodo(i, event.currentTarget.value)}
onkeydown=${event => {
switch (event.key) {
case "Enter": {
if (event.currentTarget.value) {
addTodo(i + 1);
}
break;
}
case "Backspace": {
if (event.altKey && !event.currentTarget.value) {
removeTodo(i);
event.preventDefault();
}
break;
}
}
}}>`}
${html`<button onclick=${() => removeTodo(i)}>-`}
</div>`)}
${html`<button onclick=${() => addTodo()}>+`}
</div>`);
root.value = todos;
root.dispatchEvent(new CustomEvent("input"));
}

setTodos(["clean house", "buy milk"]);
return root;
}
Insert cell
morph = require(await FileAttachment("nanomorph-5.4.2.js").url())
Insert cell
html = (await require("htl@0.2")).html
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