Form for Editing Resource

Cat 3

  • Name
    Mr. Business
  • Color
    Gray
  • Owner
    Gayle
  • Category
    Fictional

NOTE: reference the Setup section for generating the Animals context and adding the Cats to the database used in this example.

NOTE: while you can click the "Edit" link above and the "Edit Cat" button on the show page and interact with the form, editing cats is disabled for this preview. The code below will still edit cats.

scope "/", LiveViewBasicsWeb do
  pipe_through :browser

  live "/cats", CatLive.Index, :index
  live "/cats/:id", CatLive.Show, :show
  live "/cats/:id/edit", CatLive.Form, :edit
end
defmodule LiveViewBasicsWeb.CatLive.Index do
  use LiveViewBasicsWeb, :live_view

  alias LiveViewBasics.Animals

  def mount(_params, _session, socket) do
    socket = stream(socket, :cats, Animals.list_cats())
    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash}>
      <h1 class="text-4xl font-bold text-center">Form for Editing Resource</h1>
      <.header>
        Listing Cats
      </.header>
      <div class="mb-2">
        <.table
          id="cats"
          rows={@streams.cats}
          row_click={fn {_id, cat} -> JS.navigate(~p"/cats/#{cat}") end}
        >
          <:col :let={{_id, cat}} label="Name">{cat.name}</:col>
          <:col :let={{_id, cat}} label="Color">{cat.color}</:col>
          <:col :let={{_id, cat}} label="Owner">{cat.owner}</:col>
          <:col :let={{_id, cat}} label="Category">{cat.category}</:col>
          <:action :let={{_id, cat}}>
            <div class="sr-only">
              <.link navigate={~p"/cats/#{cat}"}>Show</.link>
            </div>
            <.link navigate={~p"/cats/#{cat}/edit"}>Edit</.link>
          </:action>
        </.table>
      </div>
    </Layouts.app>
    """
  end
end
defmodule LiveViewBasicsWeb.CatLive.Show do
  use LiveViewBasicsWeb, :live_view

  alias LiveViewBasics.Animals

  def mount(%{"id" => id}, _session, socket) do
    socket = assign(socket, :cat, Animals.get_cat!(id))

    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash}>
      <h1 class="text-4xl font-bold text-center">Form for Editing Resource</h1>
      <.header>
        Cat {@cat.id}
        <:actions>
          <.button navigate={~p"/cats/#{@cat}/edit"}>
            <.icon name="hero-pencil-square" /> Edit Cat
          </.button>
        </:actions>
      </.header>
      <div class="mb-2">
        <.list>
          <:item title="Name">{@cat.name}</:item>
          <:item title="Color">{@cat.color}</:item>
          <:item title="Owner">{@cat.owner}</:item>
          <:item title="Owner">{@cat.category}</:item>
        </.list>
      </div>
    </Layouts.app>
    """
  end
end
defmodule LiveViewBasicsWeb.CatLive.Form do
  use LiveViewBasicsWeb, :live_view

  alias LiveViewBasics.Animals

  def mount(params, _sessions, socket) do
    socket = apply_action(socket, socket.assigns.live_action, params)
    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash}>
      <h1 class="text-4xl font-bold text-center">Form for Editing Resource</h1>
      <.header>
        Cat Form
      </.header>

      <div class="mb-2">
        <.form for={@form} id="cat-form" phx-change="validate" phx-submit="save">
          <.input field={@form[:name]} type="text" label="Name" />
          <.input field={@form[:color]} type="text" label="Color" />
          <.input field={@form[:owner]} type="text" label="Owner" />
          <.input field={@form[:category]} type="text" label="Category" />
          <footer>
            <.button phx-disable-with="Saving...">Save Cat</.button>
          </footer>
        </.form>
      </div>
    </Layouts.app>
    """
  end

  def handle_event("validate", %{"cat" => cat_params}, socket) do
    changeset = Animals.change_cat(socket.assigns.cat, cat_params)
    {:noreply, assign(socket, form: to_form(changeset, action: :validate))}
  end

  def handle_event("save", %{"cat" => cat_params}, socket) do
    save_cat(socket, socket.assigns.live_action, cat_params)
  end

  defp apply_action(socket, :edit, %{"id" => id}) do
    cat = Animals.get_cat!(id)

    socket
    |> assign(:cat, cat)
    |> assign(:form, to_form(Animals.change_cat(cat)))
  end

  defp save_cat(socket, :edit, cat_params) do
    case Animals.update_cat(socket.assigns.cat, cat_params) do
      {:ok, cat} ->
        socket =
          socket
          |> put_flash(:info, "Cat updated successfully")
          |> push_navigate(to: ~p"/cats/#{cat}")

        {:noreply, socket}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, form: to_form(changeset))}
    end
  end
end
# The below functions already exist if you ran the context generator in the Setup
def list_cats do
  Repo.all(Cat)
end

def get_cat!(id), do: Repo.get!(Cat, id)

def change_cat(%Cat{} = cat, attrs \\ %{}) do
  Cat.changeset(cat, attrs)
end

def update_cat(%Cat{} = cat, attrs) do
  cat
  |> Cat.changeset(attrs)
  |> Repo.update()
end