# Creating Note taking app using LiveView and GenServer - Part 2

This blog is a continuation of a two-part blog. This is going to be part 2. In the [previous](https://abulasar.com/creating-note-taking-app-using-liveview-and-genserver-part-1) blog, we've seen the designing of the process layer (Boundary Layer) of the application. We implemented the GenServer and started it with Supervisor. We also tested the API layer in `iex` shell and it is working as per our expectations. In this blog, we are going to implement the UI part of the application using Phoenix Liveview.

### Plan of attack

* We are going to add different LiveView routes ✓
    
* We will implement List page displaying all notes ✓
    
* Implement detail page for note ✓
    
* Add update and delete action for the note ✓
    
* Add create note form ✓
    
* We will be integrating the API with each of these actions. ✓
    

## Let's start adding routes definition 🚧

* As discussed we are going to have 3 routes.
    
* One for "List", "detail" and one for "create".
    
* For adding route open `lib/note_app_web/router.ex` file and add following code.
    

```sql
scope "/", NoteAppWeb do
    pipe_through :browser

    # These are the new routes
    live "/", NotesIndexLive
    live "/notes/new", NotesNewLive
    live "/notes/:id/edit", NotesEditLive
  end
```

* `live` is a macro that requires 3 arguments, in this case, we are passing 2.
    
    1. Endpoint URL
        
    2. Module name of the `liveview` file associated with that endpoint.
        
* So, we are going to have 3 modules in the folder `lib/note_app_web/live`. They are
    
    1. `notes_index_live.ex`
        
    2. `notes_new_live.ex`
        
    3. `notes_edit_live.ex`.
        
* These routes are self-explanatory as per the name.
    

### Add Notes List page ✅

* Every live module acts like a controller, which is invoked as soon as we hit the route associated with that live file.
    
* Every `live` file starts with the `mount` function which acts like a constructor (in OOP sense). It takes 3 parameters
    
    * `params` =&gt;`params` has URL parameter specific data.
        
    * `session` =&gt; User session specific information.
        
    * `socket` =&gt; It acts as a `state` for every Liveview page.
        
* It returns the `ok` tuple with the `socket`.
    
* Since, this page is about the list of `notes`, we are going to query our GenServer about the list of notes it has.
    
* We are going to assign queried `list of notes` and `number of notes` to the socket variable.
    

```sql
defmodule NoteAppWeb.NotesIndexLive do
    use NoteAppWeb, :live_view
    alias NoteApp.Notes.NoteServer

    def mount(_params, _session, socket) do
       all_notes = NoteServer.all_notes()
       socket = assign(socket, :notes, all_notes)
       socket = assign(socket, :notes_length, Kernel.length(all_notes))
       {:ok, socket}
    end
end
```

* As you will notice we have `alias` the `NoteServer` module i.e GenServer. If you remember there is an `all_notes` function in it. We have called it and assigned it to the `all_notes` variable.
    
* Using the `assign` function we have assigned these `notes` to the `notes` variable.
    
* Similarly, we have assigned the number of notes to the `notes_length` variable.
    
* Now our data is ready, now we need to render the view.
    
* For that Liveview has a `render` function. We have our list of notes and their count we are going to display it in this render function.
    

```sql
   ~L"""
      <div class="notes">
        <div class="notes-header">
            <h2 class="notes-title">&#9782; Notes</h2>
            <p class="notes-count"><%= @notes_length %></p>
        </div>

        <div class="notes-list">
          <%= for note <- @notes do %>
            <%= live_patch to: Routes.live_path(@socket, NotesEditLive, note.id) do %>
              <div class="notes-list-item">
                <h3><%= note.title %></h3>
                <p><%= note.body %></p>
              </div>
            <% end %>
          <% end %>
        </div>

        <%= live_patch "+", to: Routes.live_path(@socket, NotesNewLive), class: "floating-button" %>
      </div >
    """
```

* This HTML code has lots of styling which you can copy from the `assets/app.css` file in the project repo of this blog.
    
* Rest displaying the logic of the list of notes is simple, we are just iterating over the `@notes` variable and displaying it under the `notes-list-item` div.
    
* There is `live_patch` `helper` defined twice in the view. One is used to navigate to the detail page of the particular note. The other navigate to the `create` page.
    
* This function takes the `Route.live_path` value which says where we are going to navigate and its associated params.
    
* So we are passing the `NotesEditLive` and `NotesNewLive` as value to these helpers.
    

### Add detail page for note along with edit ✄ and delete ✕ action

* Detail page is where we are going to display detail of the note title and its body.
    
* We have a separate LiveView file for it as well i.e `NotesEditLive`.
    
* We are going to add two actions `update` and `delete` in the view.
    
* We have these two methods in our `NoteServer` module as well.
    
* If you remember we added `live_patch` link to naviate to the details page. We passed `Routes.live_path(@socket, NotesEditLive, note.id)` to the `live_patch` helper.
    
* The `note.id` in the `live_path` function is nothing but path param for the detail page which generates URL something like this `notes/1/edit`.
    
* Inside the `details` LiveView mount function we are going to fetch this `id` from the `params` parameter of the mount function.
    
* Using this `id` we are going to fetch a particular note.
    
* In file `lib/note_app_web/live/notes_new_live.ex` we are going to add following `mount` function.
    

```sql
defmodule NoteAppWeb.NotesEditLive do
    alias NoteAppWeb.NotesIndexLive
    use NoteAppWeb, :live_view
    alias NoteApp.Notes.NoteServer

    def mount(%{"id" => id}, _session, socket) do
       note = NoteServer.get_note(String.to_integer(id))
      {:ok, assign(socket, :note, note)}
    end
```

* Similarly, we are going to add our view in the `render` function. There we have added the form with some `handle_events` like `phx-change` to manage change in the inputs and `phx-submit` to submit the form. (Check References for these handle\_events)
    
* We have added the `Delete` button with the `phx-click` event which handles the logic to delete the note.
    

```sql
      def handle_event("delete_note", _value, socket) do
           NoteServer.delete_note(socket.assigns.note.id)
           {:noreply,
              socket
              |> redirect(to: "/")
           }
      end
```

* Finally, we have `phx-submit` event that gets called on clicking the `Done` button, and logic for updating the note is called.
    

```sql
     def handle_event("save_note", _value, socket) do
           NoteServer.update_note(socket.assigns.note)
          {:noreply,
             socket
             |> redirect(to: "/")
           }
      end
```

* The final working code for the Notes detail Liveview is below.
    

```sql
defmodule NoteAppWeb.NotesEditLive do
    alias NoteAppWeb.NotesIndexLive
    use NoteAppWeb, :live_view
    alias NoteApp.Notes.NoteServer

    def mount(%{"id" => id}, _session, socket) do
       note = NoteServer.get_note(String.to_integer(id))
      {:ok, assign(socket, :note, note)}
    end

    def render(assigns) do
      ~L"""
        <div class="note">
            <div class="note-header">
               <h3>
                    <%= live_patch "<", to: Routes.live_path(@socket, NotesIndexLive) %>
               </h3>
               <button type="submit" form="create-note-form">Done</button>
               <button phx-click="delete_note">Delete</button>
             </div>

             <form id="create-note-form" phx-change="detect_change" phx-submit="save_note">
                <input type="text" placeholder="Add Title" value="<%= @note.title %>" name="title"/>
                 <br>
                 <br>
                 <textarea placeholder="Add note" name="body"><%= @note.body %></textarea>
             </form>
          </div >
       """
      end
    
      def handle_event("detect_change", %{"title" => title, "body" => body}, socket) do
          updated_note = %{socket.assigns.note | title: title, body: body}
         {:noreply, assign(socket, :note, updated_note)}
      end

      def handle_event("save_note", _value, socket) do
           NoteServer.update_note(socket.assigns.note)
          {:noreply,
             socket
             |> redirect(to: "/")
           }
      end

      def handle_event("delete_note", _value, socket) do
           NoteServer.delete_note(socket.assigns.note.id)
           {:noreply,
              socket
              |> redirect(to: "/")
           }
      end
end
```

### Add page for creating a new note

* The only part that is remaining is the creation of `note`.
    
* The form on the `/new` endpoint is very similar to the details page.
    
* We are navigating to this page by passing `NotesNewLive` module to `live_path`. `Routes.live_path(@socket, NotesNewLive)`
    
* In this LiveView module we are going to initialize empty variables `title` and `body` for the form and will use them in the render function.
    
* Similar to the edit page we will have handle\_events on saving the form where we are going to call the `create_note` function from our GenServer API.
    

```sql
defmodule NoteAppWeb.NotesNewLive do
  use NoteAppWeb, :live_view
  alias NoteApp.Notes.NoteServer
  alias NoteAppWeb.NotesIndexLive

  def mount(_params, _session, socket) do
    socket = assign(socket, title: "", body: "")
    {:ok, socket}
  end

  def render(assigns) do
    ~L"""
    <div class="note">
      <div class="note-header">
        <h3>
          <%= live_patch "<", to: Routes.live_path(@socket, NotesIndexLive) %>
        </h3>
        <button type="submit" form="create-note-form">Done</button>
      </div>

      <form id="create-note-form" phx-change="detect_change" phx-submit="save_note">
        <input type="text" placeholder="Add Title" value="<%= @title %>" name="title"/>
        <br>
        <br>
        <textarea placeholder="Add note" name="body"><%= @body %></textarea>
      </form>
    </div >
    """
  end

  def handle_event("detect_change", %{"title" => title, "body" => body}, socket) do
    {:noreply, assign(socket, title: title, body: body)}
  end

  def handle_event("save_note", _value, socket) do
    new_note = %{id: nil, title: socket.assigns.title, body: socket.assigns.body}
    NoteServer.create_note(new_note)
    {:noreply,
         socket
         |> redirect(to: "/")
    }
  end
end
```

So, that's our complete LiveView implementation of all CRUD functions. There is some scope of refactoring in the app like creating components for common code (which I will cover in another blog 😉). The main purpose of the blog was to introduce the concept of GenServer and LiveView. I hope you like this blog. If you have any questions then please comment below.

### References:

* [Project Repo](https://github.com/abulsayyad123/elixir-note-taking-app)
    
* [LiveView](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html)
    
* [handle\_events](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#c:handle_event/3)
