# Phoenix Todo List Tutorial
A complete beginners step-by-step tutorial
for building a Todo List in Phoenix.
100% functional. 0% JavaScript. Just `HTML`, `CSS` and `Elixir`. Fast and maintainable. ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dwyl/phoenix-todo-list-tutorial/ci.yml?label=build&style=flat-square&branch=main) [![codecov.io](https://img.shields.io/codecov/c/github/dwyl/phoenix-todo-list-tutorial/master.svg?style=flat-square)](http://codecov.io/github/dwyl/phoenix-todo-list-tutorial?branch=master) [![HitCount](http://hits.dwyl.com/dwyl/phoenix-todo-list-tutorial.svg)](http://hits.dwyl.com/dwyl/phoenix-todo-list-tutorial) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/phoenix-todo-list-tutorial/issues)
100% functional. 0% JavaScript. Just `HTML`, `CSS` and `Elixir`. Fast and maintainable. ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dwyl/phoenix-todo-list-tutorial/ci.yml?label=build&style=flat-square&branch=main) [![codecov.io](https://img.shields.io/codecov/c/github/dwyl/phoenix-todo-list-tutorial/master.svg?style=flat-square)](http://codecov.io/github/dwyl/phoenix-todo-list-tutorial?branch=master) [![HitCount](http://hits.dwyl.com/dwyl/phoenix-todo-list-tutorial.svg)](http://hits.dwyl.com/dwyl/phoenix-todo-list-tutorial) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/phoenix-todo-list-tutorial/issues)
## Why? 🤷 Todo lists are familiar to most people; we make lists all the time. _Building_ a Todo list from scratch is a great way to learn `Elixir`/`Phoenix` because the **UI/UX** is **simple**, so we can focus on implementation. For the team [**`@dwyl`**](https://github.com/dwyl) this app/tutorial is a showcase of how server side rendering (_with client side progressive enhancement_) can provide a excellent balance between developer effectiveness (_shipping features fast_), UX and _accessibility_. The server rendered pages take less than 5ms to respond so the UX is _fast_. On Fly.io: [phxtodo.fly.dev](https://phxtodo.fly.dev/) round-trip response times are sub 200ms for all interactions, so it _feels_ like a client-side rendered App.
## What? 💭 A Todo list tutorial that shows a complete beginner how to build an app in Elixir/Phoenix from scratch. ### Try it on Fly.io: [phxtodo.fly.dev](https://phxtodo.fly.dev) Try the Fly.io version. Add a few items to the list and test the functionality. ![phx-todo-list-example](https://user-images.githubusercontent.com/194400/208828566-c6986ac4-17b7-4d8d-9ff0-71b6136b8ebc.gif) Even with a full HTTP round-trip for each interaction, the response time is _fast_. Pay attention to how Chrome|Firefox|Safari waits for the response from the server before re-rendering the page. The old full page refresh of yesteryear is _gone_. Modern browsers intelligently render just the changes! So the UX approximates "native"! Seriously, try the Fly.io app on your Phone and see! ### TodoMVC In this tutorial we are using the [TodoMVC](https://github.com/dwyl/javascript-todo-list-tutorial#todomvc) CSS to simplify our UI. This has several advantages the biggest being _minimizing_ how much CSS we have to write! It also means we have a guide to which _features_ need to be implemented to achieve full functionality. > **Note**: we _love_ `CSS` for its incredible power/flexibility, but we know that not everyone like it. see: [learn-tachyons#why](https://github.com/dwyl/learn-tachyons#why) The _last_ thing we want is to waste tons of time with `CSS` in a `Phoenix` tutorial!
## Who? 👤 This tutorial is for anyone who is learning to Elixir/Phoenix. No prior experience with Phoenix is assumed/expected. We have included _all_ the steps required to build the app. > If you get stuck on any step, please open an [issue](https://github.com/dwyl/phoenix-todo-list-tutorial/issues) on GitHub where we are happy to help you get unstuck! If you feel that any line of code can use a bit more explanation/clarity, please don't hesitate to _inform_ us! We _know_ what it's like to be a beginner, it can be _frustrating_ when something does not make sense! Asking questions on GitHub helps _everyone_ to learn! Please give us feedback! 🙏 Star the repo if you found it helpful. ⭐
## _How_? 👩💻 ### Before You Start! 💡 _Before_ you attempt to _build_ the Todo List, make sure you have everything you need installed on you computer. See: [prerequisites](https://github.com/dwyl/phoenix-chat-example#0-pre-requisites-before-you-start) Once you have confirmed that you have Phoenix & PostgreSQL installed, try running the _finished_ App. ### 0. Run The _Finished_ App on Your `localhost` 💻 _Before_ you start building your own version of the Todo List App, run the _finished_ version on your `localhost` to confirm that it works. Clone the project from GitHub: ```sh git clone git@github.com:dwyl/phoenix-todo-list-tutorial.git && cd phoenix-todo-list-tutorial ``` Install dependencies and setup the database: ```sh mix setup ``` Start the Phoenix server: ```sh mix phx.server ``` Visit [`localhost:4000`](http://localhost:4000) in your web browser. You should see: ![phoenix-todo-list-on-localhost](https://user-images.githubusercontent.com/194400/83285190-bed5a580-a1d5-11ea-9154-80684cf9cc0e.gif) Now that you have the _finished_ example app running on your `localhost`,
let's build it from scratch and understand all the steps. #### Auth [Optional] When running the _finished_ example app on `localhost`, if you want try the **`login` button**, you will need to get an `AUTH_API_KEY`. [1 minute] See: [Get your `AUTH_API_KEY`](https://github.com/dwyl/auth_plug#2-get-your-auth_api_key-) ### _Build_ it! If you ran the finished app on your `localhost` (_and you really should!_),
you will need to change up a directory before starting the tutorial: ``` cd .. ``` Now you are ready to _build_!
### 1. Create a New Phoenix Project 🆕 In your terminal, create a new Phoenix app using the following [`mix`](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) command: ```sh mix phx.new app --no-dashboard --no-gettext --no-mailer ``` When prompted to install dependencies, type Y followed by Enter. > **Note**: those **flags** after the `app` name > are just to avoid creating files we don't _need_ > for this simple example. > See: > [hexdocs.pm/phoenix/Mix.Tasks.Phx.New](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html) Change into the newly created `app` directory (`cd app`) and ensure you have everything you need: ```sh mix setup ``` Start the Phoenix server: ```sh mix phx.server ``` Now you can visit [`localhost:4000`](http://localhost:4000) in your web browser. You should see something similar to: ![welcome-to-phoenix](https://user-images.githubusercontent.com/17494745/206515843-2b4da196-f039-4caf-a4d2-fc316eabb2c5.png) Shut down the Phoenix server ctrl+C. Run the tests to ensure everything works as expected: ```sh mix test ``` You should see: ```sh Compiling 16 files (.ex) Generated app app 17:49:40.111 [info] Already up ... Finished in 0.04 seconds 3 tests, 0 failures ``` Having established that the Phoenix App works as expected, let's move on to creating some files!
### 2.1 Add the `/items` Resources to `router.ex` Follow the instructions noted by the generator to add the `resources "/items", ItemController` to the `router.ex`. Open the `lib/app_web/router.ex` file and locate the line: `scope "/", AppWeb do`. Add the line to the end of the block. e.g: ```elixir scope "/", AppWeb do pipe_through :browser get "/", PageController, :index resources "/items", ItemController # this is the new line end ``` Your `router.ex` file should look like this: [`router.ex#L20`](https://github.com/dwyl/phoenix-todo-list-tutorial/blob/b158abd7f0c3fbc462a4230f07b5e5e79723a258/app/lib/app_web/router.ex#L17-L22) Now, as the terminal suggested, run `mix ecto.migrate`. This will finish setting up the database tables and run the necessary migrations so everything works properly! ### 2.2 _Run_ The App! At this point we _already_ have a functional Todo List (_if we were willing to use the default Phoenix UI_).
Try running the app on your `localhost`: Run the generated migrations with `mix ecto.migrate` then the server with: ``` mix phx.server ``` Visit: http://localhost:4000/items/new and input some data. ![todo-list-phoenix-default-ui](https://user-images.githubusercontent.com/17494745/205615474-1eef8b42-86aa-4a0e-90c3-376221570255.png) Click the "Save Item" button and you will be redirected to the "show" page: http://localhost:4000/items/1 ![todo-list-phoenix-default-ui-show-item](https://user-images.githubusercontent.com/17494745/205615709-922db20e-245d-4af0-a5e3-2bbaa29771b4.png) This is not an attractive User Experience (UX), but it _works_! Here is a _list_ of items - a "Todo List". You can visit this by clicking the `Back to items` button or by accessing the following URL http://localhost:4000/items. ![todo-list-phoenix-default-ui-show-items-list](https://user-images.githubusercontent.com/17494745/205616098-a514d2bb-af28-477a-b80a-6641c5b391a9.png) Let's improve the UX by using the TodoMVC `HTML` and `CSS`! ### 3. Create the TodoMVC UI/UX To recreate the TodoMVC UI/UX, let's borrow the `HTML` code directly from the example. Visit: http://todomvc.com/examples/vanillajs add a couple of items to the list. Then, inspect the source using your browser's [Dev Tools](https://developers.google.com/web/tools/chrome-devtools/open). e.g: ![todomvc-view-source](https://user-images.githubusercontent.com/194400/82698634-0b176780-9c63-11ea-9e1d-7aa6e2328766.png) Right-click on the source you want (e.g: `
todos
### 3.1 Paste the HTML into `index.html.eex` Open the `lib/app_web/controllers/item_html/index.html.eex` file and scroll to the bottom. Then (_without removing the code that is already there_) paste the `HTML` code we sourced from TodoMVC. > e.g: [`/lib/app_web/controllers/item_html/index.html.eex#L27-L73`](https://github.com/dwyl/phoenix-todo-list-tutorial/blob/8bcc3239d975f5b706514d1a88ea47ca57e5239a/lib/app_web/controllers/item_html/index.html.heex#L27-L73) If you attempt to run the app now and visit [http://localhost:4000/items/](http://localhost:4000/items/)
You will see this (_without the TodoMVC `CSS`_): ![before-adding-css](https://user-images.githubusercontent.com/17494745/205656501-b3170bc4-c8a7-403f-9db9-2823c839f61e.png) That's obviously not what we want, so let's get the TodoMVC `CSS` and save it in our project!
### 3.2 Save the TodoMVC CSS to `/assets/css` Visit http://todomvc.com/examples/vanillajs/node_modules/todomvc-app-css/index.css
and save the file to `/assets/css/todomvc-app.css`. e.g: [`/assets/css/todomvc-app.css`](https://github.com/dwyl/phoenix-todo-list-tutorial/blob/a341c2cbb5f1ad91897293f058a5d7bee6c1e1cc/assets/css/todomvc-app.css)
### 3.3 Import the `todomvc-app.css` in `app.scss` Open the `assets/css/app.scss` file and replace it with the following: ```css /* This file is for your main application css. */ /* @import "./phoenix.css"; */ @import "./todomvc-app.css"; ``` e.g: [`/assets/css/app.scss#L4`](https://github.com/dwyl/phoenix-todo-list-tutorial/blob/8bcc3239d975f5b706514d1a88ea47ca57e5239a/assets/css/app.css#L4)
### 3.4 _Simplify_ The Layout Template Open your `lib/app_web/components/layouts/app.html.heex` file and replace the contents with the following code: ```html
> After: [`lib/app_web/components/layouts/app.html.heex`](https://github.com/dwyl/phoenix-todo-list-tutorial/blob/8bcc3239d975f5b706514d1a88ea47ca57e5239a/lib/app_web/components/layouts/app.html.heex) `<%= @inner_content %>` is where the Todo App will be rendered. > **Note**: the `