# 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 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 ...

- Published: 2021-11-03T13:05:29.480Z
- Reading time: 7 minutes
- Tags: Elixir, Phoenix framework, liveview, genserver
- Original publication: [Hashnode](https://abulasar.com/creating-note-taking-app-using-liveview-and-genserver-part-2)
- Canonical portfolio page: [abulasar.dev](https://abulasar.dev/notes/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)

## Continue

- [All technical notes](https://abulasar.dev/notes/)
- [About Abulasar](https://abulasar.dev/about/)
- [Contact Abulasar](https://abulasar.dev/contact/)
