diff --git a/app/docs/md/get-started/tutorial.md b/app/docs/md/get-started/tutorial.md index e6a9d7f2..4c405c43 100644 --- a/app/docs/md/get-started/tutorial.md +++ b/app/docs/md/get-started/tutorial.md @@ -746,6 +746,30 @@ export async function post (req) { ``` +Now that we are serving the app from the root instead of `/todos` we need to move the `get` function from the /app/api/todos.mjs into a new /app/api/index.mjs file instead. +Cut and paste the get function from the todos.mjs into index.mjs as follows. + +```javascript +import { getTodos } from '../models/todos.mjs' + +export async function get (req) { + let todos = await getTodos() + + if (req.session.problems) { + let { problems, todo, ...session } = req.session + return { + session, + json: { problems, todos, todo } + } + } + + return { + json: { todos } + } +} +``` + + To test creating a task we can start the dev server with `npm start` and navigate to [http://localhost:3333](http://localhost:3333). Now we can enter a task in the input. We have no list of tasks yet so to test if a task was created navigate to [http://localhost:3333/todos](http://localhost:3333/todos). @@ -838,6 +862,21 @@ We will also need to update the post function on the server to respond to this. In order for the implicit submit of the form to stay the same we need to add a hidden submit button with the default submit action above our new submit. Implicit submit will use the first submit button in the form. +To handle the `toggle` query parameter add the following lines to the /app/api/todos/$id.mjs inside the top of the post function. +If the toggle parameter is present the completed flag is switched. + +```javascript + const toggle = req.query.hasOwnProperty('toggle') + const body = { ...req.body } + body.completed = toggle ? !body.completed : body.completed +``` + +The line of code that validates the task should use this modified body property instead of the passed body as follows. + +```javascript +let { problems, todo } = await validate.update({ ...req, body }) +``` + Now we have items that display, edit and delete todos. Next we need a list item to add these todo-items. @@ -921,7 +960,7 @@ export async function post (req) { ``` -Our full todo list with most features should be working now. +Our full todo list with most features are in place now. We just need to add the css for the list and item components. To do this copy the following css blocks to inside the todo-list and todo-item elements inside the ` + + ` + } +} +``` + +In order to support the filtering query parameters used in the links above we need to update the /app/api/index.mjs to filter the list accordingly. + +```javascript +import { getTodos } from '../models/todos.mjs' + +export async function get (req) { + let todos = await getTodos() + let active = todos.filter(todo => !todo.completed) + let completed = todos.filter(todo => todo.completed) + + if (req.session.problems) { + let { problems, todo, ...session } = req.session + return { + session, + json: { problems, todos, todo } + } + } + + const filter = req.query.filter + if (filter==='active') todos = active + if (filter==='completed') todos = completed + + return { + json: { todos, active, completed, filter } + } +} +``` + +To clear all completed tasks add the following new api route to respond to the new clear completed form in the footer component. + +```javascript +// /app/api/todos/completed/delete.mjs + +import { deleteTodo, getTodos } from '../../../models/todos.mjs' + +export async function post (req) { + + const session = req.session + // eslint-disable-next-line no-unused-vars + let { problems: removedProblems, ...newSession } = session + const todos = await getTodos() + const completed = todos.filter(todo=>todo.completed) + try { + await Promise.all(completed.map(todo=>deleteTodo(todo.key))) + return { + session: newSession, + location: '/' + } + } + catch (err) { + return { + session: { ...newSession, error: err.message }, + json: { error: err.message }, + location: '/' + } + } +} +``` + +And to add the styles from the Todo MVC for the footer past the following css into the todo-footer elment inside the ` + + ` +} +``` + + + +## HTML First goes far +We now have a complete todo list app with all the required functionality and not a single line of client side JavaScript. +There are additional things we could add (and we will in the next section), but if these were the requirements of a greenfield project this could be released as is for testing and feedback. +We believe this should be recommended best practice, and we think that it is by far the fastest way to get a working app. + +## Progressive Enhancement +Progressive enhancement means starting with HTML and CSS to build a working app and then incrementally improve it with a little JavaScript if necessary. +This is an incremental additive approach and it should not require building your app twice. +As previously mentioned we have a fully functional app that meets all our reqirements. +What could we add with PE? +The biggest thing that could be improved is allowing for updates to the todo list without a full page reload. + + ## JavaScript First @@ -1200,7 +1477,8 @@ The goal is to: 3. Minimal extra JavaScript 4. Avoid stalling the main UI thread with long running tasks -With the CRUDL (Create, Read, Update, Delete, and List) operations already fully implemented the simplest approach is to plug in between this exchange. A typical form post and response for a CRUD route is shown below. +With the CRUDL (Create, Read, Update, Delete, and List) operations already fully implemented the simplest approach is to plug in between this exchange. +A typical form post and response for a CRUD route is shown below. 1. **Reactive data store** to share state changes throughout the app