lusketeer
lusketeer

Reputation: 1930

LiveView throws no component for CID error in console

I have a liveview called Menu with 3 Live Component Categories, Products, and Variants

phx-click set up on each category, product, so when click on category, handle_event will return assign(socket, :products, products) ProductsComponent will products for the clicked category, and click on product, Variants will show.

And the handle_events are inside the Menu View

defmodule MyAppWeb.Admin.LocationLive.Menu do
  use MyAppWeb, :live_view

  import MyAppWeb.Admin.LocationLive.Helpers,
    only: [
      get_categories: 1,
      get_products: 2,
      get_variants: 2
    ]

  alias MyApp.Manager.Base

  @impl true
  def mount(%{"id" => location_id}, _session, socket) do
    case Base.get_location(location_id) do
      nil ->
        {:noreply, redirect(socket, Routes.admin_business_path(MyAppWeb.Endpoint, :index))}

      location ->
        {:ok,
         socket
         |> assign(:page_title, "Menu")
         |> assign(:location, location)
         |> assign(:products, [])
         |> assign(:variants, [])
         |> assign(:selected_category_id, nil)
         |> assign(:selected_product_id, nil)
         |> assign(:categories, get_categories(location)), temporary_assigns: [categories: []]}
    end
  end

  @impl true
  def handle_event(
        "show-products",
        %{"category" => category_id},
        socket
      ) do
    location = get_location(socket)

    {:noreply,
     socket
     |> assign(:products, get_products(location, category_id))
     |> assign(:variants, [])
     |> assign(:selected_category_id, category_id)}
  end

  @impl true
  def handle_event(
        "show-variants",
        %{"product" => product_id},
        socket
      ) do
    location = get_location(socket)

    {:noreply,
     socket
     |> assign(:variants, get_variants(location, product_id))
     |> assign(:selected_product_id, product_id)}
  end

  defp get_location(socket) do
    socket.assigns.location
  end
end

menu.html.leex

<div class="row">
  <div class="<%= row_parts_class(4) %>">
    <div class="align-items-center <%= row_parts_class(12) %>">
      <h5 class="h5 font-weight-bold text-default">Categories</h5>
    </div>
    <%= live_component @socket, MyAppWeb.Admin.LocationLive.CategoriesComponent,
      categories: @categories,
      location: @location,
      id: "categories-component"
    %>
  </div>
  <div class="<%= row_parts_class(4) %>">
    <div class="align-items-center <%= row_parts_class(12) %>">
      <h5 class="h5 font-weight-bold text-default">Products</h5>
    </div>
    <%= live_component @socket, MyAppWeb.Admin.LocationLive.ProductsComponent,
      products: @products,
      location: @location,
      category_id: @selected_category_id,
      id: "products-component"
    %>
  </div>
  <div class="<%= row_parts_class(4) %>">
    <div class="align-items-center <%= row_parts_class(12) %>">
      <h5 class="h5 font-weight-bold text-default">Variants</h5>
    </div>
    <%= live_component @socket, MyAppWeb.Admin.LocationLive.VariantsComponent,
      variants: @variants,
      location: @location,
      product_id: @selected_product_id,
      id: "variants-component"
    %>
  </div>
</div>

My problem is that after clicking on product, and variants are shown, then I go back to click on another category, it will show new products, but the old variants are still there. So I tried to assign(socket, :variants, []) in category handle_event, but it throws an error in console no component for CID 2, and the old Products and Variants components remain unchanged.

enter image description here

Anyone has any idea how to fix this or maybe a workaround to clear out the VariantsComponent everytime a category is clicked?

Thanks!

Upvotes: 3

Views: 338

Answers (1)

lusketeer
lusketeer

Reputation: 1930

After playing around with it, I got the variants to hide by setting selected_product_id to nil and put an if statement around the Variants live component

<%= if @selected_product_id do %>
  <%= live_component @socket, MyAppWeb.Admin.LocationLive.VariantsComponent,
    variants: @variants,
    location: @location,
    product_id: @selected_product_id,
    id: "variants-component"
  %>
<% end %>

and inside of menu

{:noreply,
 socket
 |> assign(:products, get_products(location, category_id))
 |> assign(:selected_product_id, nil)
 |> assign(:selected_category_id, category_id)}

I guess this way, when live view pushes change to the view, it will check the if it should render the live component, which ends up hiding the variants component when selected_product_id is nil

Upvotes: 0

Related Questions