0

This seems to be strange for me, but without any updates of libraries or even elixir part of app doesnt work like before.

I have got few views which show list of products, categories, brands etc. Problem seems to be repeated everytime being in show window. Instead of adding to cart or refuse adding to cart it invokes error with event_handler from index window. I will paste just code from ex and html for one of those, because code is similar everywhere and problem seems to happens everytime (sometimes it works if I open VSCode and add IO.inspect() on handler an save it (LOL), but after few tries it crashes again)

category_index.ex

@impl true
  def mount(_params, %{"user_token" => user_token}, socket) do
    user = Accounts.get_user_by_session_token(user_token)

    {:ok,
      socket
      |> assign(:current_user, user)
      |> assign(:categories, Catalog.list_categories())}
  end

  def mount(_params, _session, socket) do
    {:ok, assign(socket, :categories, Catalog.list_categories())}
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :show, %{"id" => id}) do
    socket
      |> assign(:page_title, "Show Category")
      |> assign(:category, Catalog.get_category!(id))
      |> assign(:products, Catalog.get_available_products_by_category_id(id))
  end

  defp apply_action(socket, :index, _params) do
    socket
    |> assign(:page_title, "Listing Categories")
    |> assign(:category, nil)
  end
end

category_index.html.heex

<div class="bg-white mx-auto h-screen justify-items-center">
<section class="mx-auto max-w-screen-lg justify-items-center mt-10 mb-5">
  <img
    alt="category image"
    src={ ~s[/images/main-site-photo.jpg]}>
  </section>
  <div class="mx-auto mb-10">
    <p class="text-center text-blue-500 md:text-2xl sm:text-xl">The best equipment for your office</p>
  </div>
  <div class="grid grid-cols-1 md:grid-cols-3 mx-auto justify-center max-w-7xl">
    <%= for category <- @categories do %>
      <%= live_redirect to: Routes.category_show_path(@socket, :show, category.id) do %>
        <div class="flex flex-col content-between justify-center mx-auto my-10 " id={"category-#{category.id}"}>
          <div class="self-center w-64 h-64">
            <img
              alt="category image" width="250" height="250"
              src={ Routes.static_path(@socket, category.image_upload || ~s[/images/default-thumbnail.jpg])} >
          </div>
          <p class="text-center text-blue-500 md:text-2xl sm:text-xl mt-5"><%= category.name %></p>
        </div>
      <% end %>
    <% end %>
  </div>
</div>

As Its written - this window contains only redirections to specific categories and list of products in it. Zero event_handlers, I dont even know if I need handle_params here…

and

category_show.ex

@impl true

  def mount(_params, %{"user_token" => user_token}, socket) do
    user = Accounts.get_user_by_session_token(user_token)

    {:ok,
      socket
      |> assign(:current_user, user)
      |> assign(:cart, ShoppingCart.get_cart_by_user_id(user.id))
      |> assign(:cart_items, %CartItem{})}
  end

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  @impl true
  def handle_event("add_to_cart", %{"product" => product_id, "quantity" => quantity}, socket) do
    IO.inspect(product_id)
    IO.inspect(quantity)
    case socket.assigns[:current_user] do
      %Eshopy.Accounts.User{role: :user} ->
        create_and_add_item(product_id, quantity, socket)

      _ ->
      {:noreply,
        socket
        |> put_flash(:info, "You must be logged in")}
    end
  end

  @impl true
  def handle_params(%{"id" => id}, _, socket) do
    {:noreply,
      socket
      |> assign(:page_title, "Show Category")
      |> assign(:category, Catalog.get_category!(id))
      |> assign(:products, Catalog.get_available_products_by_category_id(id))}
  end

  defp create_and_add_item(product_id, quantity, socket) do
    product = Catalog.get_product!(product_id)
    quantity = String.to_integer(quantity)

    socket =
      case ShoppingCart.get_cart_by_user_id(socket.assigns.current_user.id) do
        %Cart{} = cart ->
          add_item_to_shopping_cart(socket, cart, product, quantity)

        nil ->
          {:ok, %Cart{} = cart} = ShoppingCart.create_cart(socket.assigns.current_user)
          add_item_to_shopping_cart(socket, cart, product, quantity)
      end

    {:noreply, socket}
  end

  defp add_item_to_shopping_cart(socket, cart, product, quantity) do
    case ShoppingCart.add_item_to_cart(cart, product, quantity) do
          {:ok, _item} ->
            socket
            |> put_flash(:info, "Item added to shopping cart")

          {:error, _changeset} ->
            socket
            |> put_flash(:info, "Error with adding item")
    end
  end
end

category_show.html.heex

<div>
    <p class="text-center text-blue-500 md:text-2xl text-xl"><strong><%= @category.name %></strong></p>
    <div class="flex flex-wrap mx-auto justify-center max-w-7xl">
        <%= for product <- @products do %>
          <div class="flex flex-col mx-auto my-5">
            <%= live_redirect to: Routes.product_show_path(@socket, :show, product.id) do %>
              <div class="grid grid-cols-1 content-center justify-center mx-auto" id={"product-#{product.id}"}>
                <div class="self-center w-64 h-64">
                  <img
                    alt="product image" width="250" height="250"
                    src={ product.image_upload } >
                </div>
                    <p class="text-center text-blue-500 md:text-2xl sm:text-xl mt-5"><strong><%= product.name %></strong></p>
                    <p class="text-center text-blue-500 md:text-xl sm:text-xl"><%= Catalog.get_category!(product.category_id).name %></p>
                    <p class="text-center text-blue-500 md:text-2xl sm:text-xl"><em><%= product.unit_price %>$</em></p>
              </div>
            <% end %>
            <button class="bg-blue-400 text-white font-[Poppins] duration-500 px-6 py-2 md:my-0 hover:bg-blue-600 rounded" phx-click="add_to_cart" phx-value-product={product.id} phx-value-quantity={1}>Add to cart</button>
          </div>
        <% end %>
    </div>
</div>

Being in show window I click add_to_cart. It doesnt matter if I am logged in or not it crashes and redirects me to category_index page (even if i receive flash that Product has been added to cart :D) and terminal becomes red with error like that:

I paste all of it, maybe someone catches things that i can not.

[error] GenServer #PID<0.684.0> terminating
** (UndefinedFunctionError) function EshopyWeb.CategoryLive.Index.handle_event/3 is undefined or private
    (eshopy 0.1.0) EshopyWeb.CategoryLive.Index.handle_event("add_to_cart", %{"product" => "5", "quantity" => "1", "value" => ""}, #Phoenix.LiveView.Socket<assigns: %{__changed__: %{}, categories: [%Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 3, image_upload: "/images/live_view_upload-1675197743-83913940887-3", inserted_at: ~N[2023-01-31 20:42:26], name: "Phones", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:42:26]}, %Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 4, image_upload: "/images/live_view_upload-1675197756-749924054466-3", inserted_at: ~N[2023-01-31 20:42:41], name: "Mouses", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:42:41]}, %Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 1, image_upload: "/images/live_view_upload-1675197713-196034875224-5", inserted_at: ~N[2023-01-31 20:41:57], name: "Notebook", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-02-05 04:15:35]}, %Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 8, image_upload: "/images/live_view_upload-1675624630-27014369202-3", inserted_at: ~N[2023-02-05 19:17:11], name: "Tablets", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-02-05 19:17:11]}], category: nil, flash: %{}, live_action: :index, page_title: "Listing Categories"}, endpoint: EshopyWeb.Endpoint, id: "phx-F0Sv5GnnZQLaTQFB", parent_pid: nil, root_pid: #PID<0.684.0>, router: EshopyWeb.Router, transport_pid: #PID<0.679.0>, view: EshopyWeb.CategoryLive.Index, ...>)
    (phoenix_live_view 0.17.12) lib/phoenix_live_view/channel.ex:382: anonymous fn/3 in Phoenix.LiveView.Channel.view_handle_event/3
    (telemetry 1.1.0) /home/mateusz/Pulpit/eshopy/deps/telemetry/src/telemetry.erl:320: :telemetry.span/3
    (phoenix_live_view 0.17.12) lib/phoenix_live_view/channel.ex:216: Phoenix.LiveView.Channel.handle_info/2
    (stdlib 4.0.1) gen_server.erl:1120: :gen_server.try_dispatch/4
    (stdlib 4.0.1) gen_server.erl:1197: :gen_server.handle_msg/6
    (stdlib 4.0.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: %Phoenix.Socket.Message{event: "event", join_ref: "4", payload: %{"event" => "add_to_cart", "type" => "click", "value" => %{"product" => "5", "quantity" => "1", "value" => ""}}, ref: "6", topic: "lv:phx-F0Sv5GnnZQLaTQFB"}
State: %{components: {%{}, %{}, 1}, join_ref: "4", serializer: Phoenix.Socket.V2.JSONSerializer, socket: #Phoenix.LiveView.Socket<assigns: %{__changed__: %{}, categories: [%Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 3, image_upload: "/images/live_view_upload-1675197743-83913940887-3", inserted_at: ~N[2023-01-31 20:42:26], name: "Phones", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:42:26]}, %Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 4, image_upload: "/images/live_view_upload-1675197756-749924054466-3", inserted_at: ~N[2023-01-31 20:42:41], name: "Mouses", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:42:41]}, %Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 1, image_upload: "/images/live_view_upload-1675197713-196034875224-5", inserted_at: ~N[2023-01-31 20:41:57], name: "Notebook", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-02-05 04:15:35]}, %Eshopy.Catalog.Category{__meta__: #Ecto.Schema.Metadata<:loaded, "categories">, id: 8, image_upload: "/images/live_view_upload-1675624630-27014369202-3", inserted_at: ~N[2023-02-05 19:17:11], name: "Tablets", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-02-05 19:17:11]}], category: nil, flash: %{}, live_action: :index, page_title: "Listing Categories"}, endpoint: EshopyWeb.Endpoint, id: "phx-F0Sv5GnnZQLaTQFB", parent_pid: nil, root_pid: #PID<0.684.0>, router: EshopyWeb.Router, transport_pid: #PID<0.679.0>, view: EshopyWeb.CategoryLive.Index, ...>, topic: "lv:phx-F0Sv5GnnZQLaTQFB", upload_names: %{}, upload_pids: %{}}

To make it works I need to copy/paste all handlers to index.ex what sounds like a bull***t. Recently I started using socket and channels to track users - after that feature it started to showing me that error. Is is possible that its the reason? Logically it shouldnt be…

I tried to play with it.

I added function to category_index.ex:

@impl true
  def handle_event("add_to_cart", _, socket) do
    {:noreply, socket}
  end

And now category_show is working well. I add product to cart, and only flash appears. Being logged out flash appears, but i cant add to cart anything. Like it should work.

Otherwise without putting “empty” handler other views dont work. In brand_show view after clicking button I got:

Flash: "Item added to shopiing cart. (And it really appears in cart :D)

Redirects to: brand_index view (it should never happen).

Error:

[error] GenServer #PID<0.3285.0> terminating
** (UndefinedFunctionError) function EshopyWeb.BrandLive.Index.handle_event/3 is undefined or private
    (eshopy 0.1.0) EshopyWeb.BrandLive.Index.handle_event("add_to_cart", %{"product" => "5", "quantity" => "1", "value" => ""}, #Phoenix.LiveView.Socket<assigns: %{__changed__: %{}, brand: nil, brands: [%Eshopy.Catalog.Brand{__meta__: #Ecto.Schema.Metadata<:loaded, "brands">, id: 1, image_upload: "/images/live_view_upload-1675197775-472722086641-2", inserted_at: ~N[2023-01-31 20:42:59], name: "Huawei", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:42:59]}, %Eshopy.Catalog.Brand{__meta__: #Ecto.Schema.Metadata<:loaded, "brands">, id: 2, image_upload: "/images/live_view_upload-1675197790-688965978619-1", inserted_at: ~N[2023-01-31 20:43:11], name: "Apple", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:43:11]}, %Eshopy.Catalog.Brand{__meta__: #Ecto.Schema.Metadata<:loaded, "brands">, id: 3, image_upload: "/images/live_view_upload-1675197802-989508123695-6", inserted_at: ~N[2023-01-31 20:43:24], name: "Logitech", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:43:24]}], current_user: #Eshopy.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "users">, confirmed_at: nil, customer: #Ecto.Association.NotLoaded<association :customer is not loaded>, email: "admin@pl", id: 1, inserted_at: ~N[2023-01-31 20:37:48], role: :user, updated_at: ~N[2023-02-08 16:52:14], ...>, flash: %{}, live_action: :index, page_title: "Listing Brands"}, endpoint: EshopyWeb.Endpoint, id: "phx-F0SskhP04L3JtRGC", parent_pid: nil, root_pid: #PID<0.3285.0>, router: EshopyWeb.Router, transport_pid: #PID<0.3267.0>, view: EshopyWeb.BrandLive.Index, ...>)
    (phoenix_live_view 0.17.12) lib/phoenix_live_view/channel.ex:382: anonymous fn/3 in Phoenix.LiveView.Channel.view_handle_event/3
    (telemetry 1.1.0) /home/mateusz/Pulpit/eshopy/deps/telemetry/src/telemetry.erl:320: :telemetry.span/3
    (phoenix_live_view 0.17.12) lib/phoenix_live_view/channel.ex:216: Phoenix.LiveView.Channel.handle_info/2
    (stdlib 4.0.1) gen_server.erl:1120: :gen_server.try_dispatch/4
    (stdlib 4.0.1) gen_server.erl:1197: :gen_server.handle_msg/6
    (stdlib 4.0.1) proc_lib.erl:250: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{event: "event", join_ref: "7", payload: %{"event" => "add_to_cart", "type" => "click", "value" => %{"product" => "5", "quantity" => "1", "value" => ""}}, ref: "9", topic: "lv:phx-F0SskhP04L3JtRGC"}
State: %{components: {%{}, %{}, 1}, join_ref: "7", serializer: Phoenix.Socket.V2.JSONSerializer, socket: #Phoenix.LiveView.Socket<assigns: %{__changed__: %{}, brand: nil, brands: [%Eshopy.Catalog.Brand{__meta__: #Ecto.Schema.Metadata<:loaded, "brands">, id: 1, image_upload: "/images/live_view_upload-1675197775-472722086641-2", inserted_at: ~N[2023-01-31 20:42:59], name: "Huawei", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:42:59]}, %Eshopy.Catalog.Brand{__meta__: #Ecto.Schema.Metadata<:loaded, "brands">, id: 2, image_upload: "/images/live_view_upload-1675197790-688965978619-1", inserted_at: ~N[2023-01-31 20:43:11], name: "Apple", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:43:11]}, %Eshopy.Catalog.Brand{__meta__: #Ecto.Schema.Metadata<:loaded, "brands">, id: 3, image_upload: "/images/live_view_upload-1675197802-989508123695-6", inserted_at: ~N[2023-01-31 20:43:24], name: "Logitech", products: #Ecto.Association.NotLoaded<association :products is not loaded>, updated_at: ~N[2023-01-31 20:43:24]}], current_user: #Eshopy.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "users">, confirmed_at: nil, customer: #Ecto.Association.NotLoaded<association :customer is not loaded>, email: "admin@pl", id: 1, inserted_at: ~N[2023-01-31 20:37:48], role: :user, updated_at: ~N[2023-02-08 16:52:14], ...>, flash: %{}, live_action: :index, page_title: "Listing Brands"}, endpoint: EshopyWeb.Endpoint, id: "phx-F0SskhP04L3JtRGC", parent_pid: nil, root_pid: #PID<0.3285.0>, router: EshopyWeb.Router, transport_pid: #PID<0.3267.0>, view: EshopyWeb.BrandLive.Index, ...>, topic: "lv:phx-F0SskhP04L3JtRGC", upload_names: %{}, upload_pids: %{}}
  • After updating elixir, phoenix and liveview it seems that there are more errors. Except this one, there are also errors while deleting - Ecto.StaleEntryError. I have never seen that before, and all documentations say almost nothing about that. – Mateusz Babski Feb 18 '23 at 22:03

1 Answers1

0

From the error itself I would assume that you are missing phx-target on the button where you set phx-click attribute and your event goes to the wrong LiveView module - hence the error that it cannot find implementation for the given event. Have a look into docs about LiveComponents and phx-target attribute here: https://hexdocs.pm/phoenix_live_view/Phoenix.LiveComponent.html

Kris
  • 5,714
  • 2
  • 27
  • 47