Hi all,
I have multiple models which are affected here:
customers
products
orders
whichbelong_to
customer
andhave_many
orderlines
orderlines
whichbelong_to
product
andbelong_to
order
I have a LiveView for orders, which was created via mix phx.gen.live
.
The generated template view did only include fields for standard fields like name
, which are not associated. What I additional want to do is to create orderlines from within the LiveViews :new and :edit actions.
I tried my way through different places in the docs but was not able to fit everything together:
In the Phoenix.Component docs there is something about embeds_many
which I adapted to has_many
, so that the example would look as follow:
defmodule PhoenixRise.Orders.Order do
use Ecto.Schema
import Ecto.Changeset
schema "orders" do
field :name, :string
field :state, Ecto.Enum, values: [:draft, :cancel, :confirmed, :in_process, :done]
belongs_to :customer, PhoenixRise.Contacts.Contact
has_many :orderlines, PhoenixRise.Orders.Orderline, on_replace: :delete
has_many :products, through: [:orderlines, :product]
timestamps()
end
@doc false
def changeset(order, attrs) do
order
|> cast(attrs, [:name, :state, :customer_id])
|> cast_assoc(:orderlines,
sort_param: :orderlines_sort,
drop_param: :orderlines_drop
)
|> validate_required([:name, :state, :customer_id])
|> unique_constraint(:name)
end
end
The render
-Function for my LiveView FormComponent
is as follows:
def render(assigns) do
~H"""
<div>
<.header>
<%= @title %>
<:subtitle>Use this form to manage order records in your database.</:subtitle>
</.header>
<.simple_form
for={@form}
id="order-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input field={@form[:name]} label="Name" />
<.input field={@form[:state]} label="State" type="select" options={[{"Draft", "draft"}, {"Confirmed", "confirmed"}]}/>
<.input field={@form[:customer_id]} label="Customer" />
<.inputs_for :let={o} field={@form[:orderlines]}>
<input type="hidden" name="order[orderlines_sort][]" value={o.index} />
<.input field={o[:product_qty]} placeholder="Quantity" />
<.input field={o[:product_id]} placeholder="Product" />
<.input field={o[:product_unit_price]} placeholder="Price" />
<label>
<input type="checkbox" name="order[orderlines_drop][]" value={o.index} class="hidden" />
<.icon name="hero-x-mark" class="w-6 h-6 relative top-2" />
</label>
</.inputs_for>
<label class="block cursor-pointer">
<input type="checkbox" name="order[orderlines_sort][]" class="hidden" />
add orderline
</label>
<input type="hidden" name="order[orderlines_drop][]" />
<:actions>
<.button phx-disable-with="Saving...">Save Order</.button>
</:actions>
</.simple_form>
</div>
"""
end
I am aware, that the fields associated by belongs_to
have to be filled with the corresponding ids. But that will be the next step. At first, I want to be able to create and delete orderlines from inside the orders form. With the given code, I can create orders without orderlines, but as soon as I add an orderline, the order is just not saved. There is no error message, so I am kind of puzzeling, how to archive this.
Thanks and have a nice weekend,
Michael