Hi I decided to make another attemp to learn basics of LiveView. For learning purpose i’ve chosen absolutely simple fake ecommerce site.
I want to implement “add to cart” button that triggers adding one product to cart (from main site) or chosen quantity products to cart(from exact product cart). For now I’m struggling with handling the simple one.
I have a category view (show.html.heex) that creates div with products and on the bottom there is a button:
<%= for product <- @products do %>
<%= live_patch to: Routes.product_show_path(@socket, :show, product.id) do %>
<p class="text-center text-blue-500 md:text-2xl sm:text-xl mt-5"><strong><%= product.name %></strong></p>
<button class="bg-blue-400 text-white font-[Poppins] duration-500 px-6 py-2 mx-4 my-4 md:my-0 hover:bg-blue-600 rounded"><%= link "Cart!", to: "#", phx_click: "add_to_cart", phx_value_id: product.id %>
</button>
</div>
<% end %>
<% end %>
My whole show.ex looks like this:
@impl true
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(:cart_items, nil)}
end
@impl true
def handle_event("add_to_cart", %{"product_id" => product_id, "quantity" => quantity}, socket) do
product = Catalog.get_product!(product_id)
case ShoppingCart.get_cart_by_user_id(socket.assigns.current_user.id) do
{:ok, cart} ->
add_item_to_shopping_cart(socket, cart, product, quantity)
{:error, _} ->
cart = ShoppingCart.create_cart(socket.assigns.current_user)
add_item_to_shopping_cart(socket, cart, product, quantity)
end
{:noreply, socket}
end
@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:category, Catalog.get_category!(id))
|> assign(:products, Catalog.get_product_by_category_id(id))}
end
def handle_params(%{"id" => product_id, "quantity" => 1}, _, socket) do
{:noreply,
socket
|> assign(:products, Catalog.get_product!(product_id))
|> assign(:cart_items, ShoppingCart.create_cart_item())}
end
defp page_title(:show), do: "Show Category"
defp page_title(:edit), do: "Edit Category"
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")
|> redirect(to: Routes.cart_show_path(socket, :show, cart))
{:error, _changeset} ->
socket
|> put_flash(:info, "Error with adding item")
|> redirect(to: Routes.cart_show_path(socket, :show, cart))
end
end
I tried hard code quantity from this layer because there will be always 1, but it doesnt work either. It looks like every time function matches phx_value_id to category not to a product.
Is there an obvious way that I cant find to just pass product.id through button to handle_event (or from product view also quantity from select or input) or i need to create controller instead of using liveview and there make ‘create’ function to do whole work?
Sorry for messy post I have to go to work and I tried to solve problem before it. If You have more questions I’ll reply them after coming back.
Greetings