Todo App Code Checkpoints
Below are checkpoints for the application build in the Frontend Masters's Reactivity with SolidJS course. The checkpoints line up with the lesson names in the course. For example, if you are stuck in the Modifying Todos
lesson, you can find the completed code in the cooresponding checkpoint below.
Lesson Checkpoints
Checkpoint 1: Building a Todo App
javascript
// File: App.jsximport { createSignal, Show } from 'solid-js';const App = () => {const [todos, setTodos] = createSignal([{id: 1,title: "Learn SolidJS",completed: false}]);return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"/></header><Show when={todos().length > 0}><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<li class="todo"><div class="view"><inputtype="checkbox"class="toggle" /><label>{todo.title}</label><button class="destroy" /></div></li>)}</For></ul></Show></section>);};export default App;
javascript
// File: App.jsximport { createSignal, Show } from 'solid-js';const App = () => {const [todos, setTodos] = createSignal([{id: 1,title: "Learn SolidJS",completed: false}]);return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"/></header><Show when={todos().length > 0}><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<li class="todo"><div class="view"><inputtype="checkbox"class="toggle" /><label>{todo.title}</label><button class="destroy" /></div></li>)}</For></ul></Show></section>);};export default App;
Checkpoint 2: Creating New Todos
javascript
// File: App.jsximport { createSignal, createMemo, Show, onCleanup } from 'solid-js';let counter = 0;const ESCAPE_KEY = 27;const ENTER_KEY = 13;const App = () => {const [todos, setTodos] = createSignal([]);const addTodo = (event) => {const title = event.target.value.trim();if (event.keyCode === ENTER_KEY && title) {setTodos((todos) => [...todos,{ id: counter++, title, completed: false },]);event.target.value = '';}};return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"onKeyDown={addTodo}/></header><Show when={todos().length > 0}><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<li class="todo"><div class="view"><inputtype="checkbox"class="toggle" /><label>{todo.title}</label><button class="destroy" /></div></li>)}</For></ul></Show></section>);};export default App;
javascript
// File: App.jsximport { createSignal, createMemo, Show, onCleanup } from 'solid-js';let counter = 0;const ESCAPE_KEY = 27;const ENTER_KEY = 13;const App = () => {const [todos, setTodos] = createSignal([]);const addTodo = (event) => {const title = event.target.value.trim();if (event.keyCode === ENTER_KEY && title) {setTodos((todos) => [...todos,{ id: counter++, title, completed: false },]);event.target.value = '';}};return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"onKeyDown={addTodo}/></header><Show when={todos().length > 0}><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<li class="todo"><div class="view"><inputtype="checkbox"class="toggle" /><label>{todo.title}</label><button class="destroy" /></div></li>)}</For></ul></Show></section>);};export default App;
Checkpoint 3: Modifying Todos
javascript
// File: App.jsximport { createSignal, createMemo, Show } from 'solid-js';let counter = 0;const ESCAPE_KEY = 27;const ENTER_KEY = 13;const App = () => {const [todos, setTodos] = createSignal([]);const remainingCount = createMemo(() => todos().length - todos().filter((todo) => todo.completed).length);const addTodo = (event) => {const title = event.target.value.trim();if (event.keyCode === ENTER_KEY && title) {setTodos((todos) => [...todos,{ id: counter++, title, completed: false },]);event.target.value = '';}};const toggle = (todoId) => {setTodos((todos) =>todos.map((todo) => {if (todo.id !== todoId) return todo;return { ...todo, completed: !todo.completed };}));};const remove = (todoId) => {setTodos((todos) => todos.filter((todo) => todoId !== todo.id));};const toggleAll = (event) => {const completed = event.target.checked;setTodos((todos) => todos.map((todo) => ({ ...todo, completed })));};return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"onKeyDown={addTodo}/></header><Show when={todos().length > 0}><section class="main"><inputid="toggle-all"class="toggle-all"type="checkbox"checked={!remainingCount()}onInput={toggleAll}/><label for="toggle-all" /><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<liclass="todo"classList={{completed: todo.completed,}}><div class="view"><inputtype="checkbox"class="toggle"checked={todo.completed}onInput={() => toggle(todo.id)}/><label>{todo.title}</label><button class="destroy" onClick={() => remove(todo.id)} /></div></li>)}</For></ul></section></Show></section>);};export default App;
javascript
// File: App.jsximport { createSignal, createMemo, Show } from 'solid-js';let counter = 0;const ESCAPE_KEY = 27;const ENTER_KEY = 13;const App = () => {const [todos, setTodos] = createSignal([]);const remainingCount = createMemo(() => todos().length - todos().filter((todo) => todo.completed).length);const addTodo = (event) => {const title = event.target.value.trim();if (event.keyCode === ENTER_KEY && title) {setTodos((todos) => [...todos,{ id: counter++, title, completed: false },]);event.target.value = '';}};const toggle = (todoId) => {setTodos((todos) =>todos.map((todo) => {if (todo.id !== todoId) return todo;return { ...todo, completed: !todo.completed };}));};const remove = (todoId) => {setTodos((todos) => todos.filter((todo) => todoId !== todo.id));};const toggleAll = (event) => {const completed = event.target.checked;setTodos((todos) => todos.map((todo) => ({ ...todo, completed })));};return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"onKeyDown={addTodo}/></header><Show when={todos().length > 0}><section class="main"><inputid="toggle-all"class="toggle-all"type="checkbox"checked={!remainingCount()}onInput={toggleAll}/><label for="toggle-all" /><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<liclass="todo"classList={{completed: todo.completed,}}><div class="view"><inputtype="checkbox"class="toggle"checked={todo.completed}onInput={() => toggle(todo.id)}/><label>{todo.title}</label><button class="destroy" onClick={() => remove(todo.id)} /></div></li>)}</For></ul></section></Show></section>);};export default App;
Checkpoint 4: View Filters & Clearning Completed
This is the final step for building the Todo application. You can also view the completed code and test out the application on Stackblitz
javascript
// File: App.jsximport { createSignal, createMemo, Show, onCleanup } from 'solid-js';let counter = 0;const ESCAPE_KEY = 27;const ENTER_KEY = 13;const App = () => {const [todos, setTodos] = createSignal([]);const [showMode, setShowMode] = createSignal('all');const remainingCount = createMemo(() => todos().length - todos().filter((todo) => todo.completed).length);const addTodo = (event) => {const title = event.target.value.trim();if (event.keyCode === ENTER_KEY && title) {setTodos((todos) => [...todos,{ id: counter++, title, completed: false },]);event.target.value = '';}};const toggle = (todoId) => {setTodos((todos) =>todos.map((todo) => {if (todo.id !== todoId) return todo;return { ...todo, completed: !todo.completed };}));};const remove = (todoId) => {setTodos((todos) => todos.filter((todo) => todoId !== todo.id));};const toggleAll = (event) => {const completed = event.target.checked;setTodos((todos) => todos.map((todo) => ({ ...todo, completed })));};const clearCompleted = () => {setTodos((todos) => todos.filter((todo) => !todo.completed));};const filterTodos = (todos) => {if (showMode() === 'active') return todos.filter((todo) => !todo.completed);else if (showMode() === 'completed')return todos.filter((todo) => todo.completed);return todos;};const locationHandler = () => {setShowMode(location.hash.slice(2) || 'all');};window.addEventListener('hashchange', locationHandler);onCleanup(() => window.removeEventListener('hashchange', locationHandler));return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"onKeyDown={addTodo}/></header><Show when={todos().length > 0}><section class="main"><inputid="toggle-all"class="toggle-all"type="checkbox"checked={!remainingCount()}onInput={toggleAll}/><label for="toggle-all" /><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<liclass="todo"classList={{completed: todo.completed,}}><div class="view"><inputtype="checkbox"class="toggle"checked={todo.completed}onInput={() => toggle(todo.id)}/><label>{todo.title}</label><button class="destroy" onClick={() => remove(todo.id)} /></div></li>)}</For></ul></section><footer class="footer"><span class="todo-count"><strong>{remainingCount()}</strong>{remainingCount() === 1 ? ' item ' : ' items '}left</span><ul class="filters"><li><a href="#/" classList={{ selected: showMode() === 'all' }}>All</a></li><li><ahref="#/active"classList={{ selected: showMode() === 'active' }}>Active</a></li><li><ahref="#/completed"classList={{ selected: showMode() === 'completed' }}>Completed</a></li></ul><Show when={remainingCount() !== todos().length}><button class="clear-completed" onClick={clearCompleted}>Clear completed</button></Show></footer></Show></section>);};export default App;
javascript
// File: App.jsximport { createSignal, createMemo, Show, onCleanup } from 'solid-js';let counter = 0;const ESCAPE_KEY = 27;const ENTER_KEY = 13;const App = () => {const [todos, setTodos] = createSignal([]);const [showMode, setShowMode] = createSignal('all');const remainingCount = createMemo(() => todos().length - todos().filter((todo) => todo.completed).length);const addTodo = (event) => {const title = event.target.value.trim();if (event.keyCode === ENTER_KEY && title) {setTodos((todos) => [...todos,{ id: counter++, title, completed: false },]);event.target.value = '';}};const toggle = (todoId) => {setTodos((todos) =>todos.map((todo) => {if (todo.id !== todoId) return todo;return { ...todo, completed: !todo.completed };}));};const remove = (todoId) => {setTodos((todos) => todos.filter((todo) => todoId !== todo.id));};const toggleAll = (event) => {const completed = event.target.checked;setTodos((todos) => todos.map((todo) => ({ ...todo, completed })));};const clearCompleted = () => {setTodos((todos) => todos.filter((todo) => !todo.completed));};const filterTodos = (todos) => {if (showMode() === 'active') return todos.filter((todo) => !todo.completed);else if (showMode() === 'completed')return todos.filter((todo) => todo.completed);return todos;};const locationHandler = () => {setShowMode(location.hash.slice(2) || 'all');};window.addEventListener('hashchange', locationHandler);onCleanup(() => window.removeEventListener('hashchange', locationHandler));return (<section class="todoapp"><header class="header"><h1>Todos</h1><inputclass="new-todo"placeholder="What needs to be done?"onKeyDown={addTodo}/></header><Show when={todos().length > 0}><section class="main"><inputid="toggle-all"class="toggle-all"type="checkbox"checked={!remainingCount()}onInput={toggleAll}/><label for="toggle-all" /><ul class="todo-list"><For each={filterTodos(todos())}>{(todo) => (<liclass="todo"classList={{completed: todo.completed,}}><div class="view"><inputtype="checkbox"class="toggle"checked={todo.completed}onInput={() => toggle(todo.id)}/><label>{todo.title}</label><button class="destroy" onClick={() => remove(todo.id)} /></div></li>)}</For></ul></section><footer class="footer"><span class="todo-count"><strong>{remainingCount()}</strong>{remainingCount() === 1 ? ' item ' : ' items '}left</span><ul class="filters"><li><a href="#/" classList={{ selected: showMode() === 'all' }}>All</a></li><li><ahref="#/active"classList={{ selected: showMode() === 'active' }}>Active</a></li><li><ahref="#/completed"classList={{ selected: showMode() === 'completed' }}>Completed</a></li></ul><Show when={remainingCount() !== todos().length}><button class="clear-completed" onClick={clearCompleted}>Clear completed</button></Show></footer></Show></section>);};export default App;