AE
Ash Elixir•3y ago
axdc

LiveView interface for {:array, :string} type

I'm making a LiveView interface to edit a resource with an {:array, :string} Ash type attribute and I'm looking for up-to-date, Ash-aware best practices. I've cobbled a few prototypes together but I feel like I'm missing something fundamental and getting hacky. Is there any documentation on the idiomatic way to accomplish this?
11 Replies
ZachDaniel
ZachDaniel•3y ago
It depends a bit on exactly what you're trying to do. You should be able to use a combination of AshPhoenix.Form.update_form for adding/removing values, as well as a loop over the values. Here is some pseudocode/ideas you may be able to use.
for {value, index} <- Enum.with_index(AshPhoenix.Form.value(@form, :list)) do
<.input value={value} ... name={"parent_form_name[field_name][]"} ...>

<button phx-click="add_thing_to_list" phx-value-path={"parent_form_name"}/>
end

def handle_event("add_thing_to_list", %{"path" => path}, socket) do
new_form = AshPhoenix.Form.update_form(socket.assigns.form, path, fn child_form ->
new_value = AshPhoenix.Form.value(form, :field_name) ++ [""]

AshPhoenix.Form.validate(form, Map.put(AshPhoenix.Form.params(form), "field_name", new_value))
end)
{:noreply, assign(socket, :form, new_form)}
end
for {value, index} <- Enum.with_index(AshPhoenix.Form.value(@form, :list)) do
<.input value={value} ... name={"parent_form_name[field_name][]"} ...>

<button phx-click="add_thing_to_list" phx-value-path={"parent_form_name"}/>
end

def handle_event("add_thing_to_list", %{"path" => path}, socket) do
new_form = AshPhoenix.Form.update_form(socket.assigns.form, path, fn child_form ->
new_value = AshPhoenix.Form.value(form, :field_name) ++ [""]

AshPhoenix.Form.validate(form, Map.put(AshPhoenix.Form.params(form), "field_name", new_value))
end)
{:noreply, assign(socket, :form, new_form)}
end
I think there is some opportunities for utility functions there like AshPhoenix.Form.update_param(form, "field_name", fn value -> value ++ [""] end) that will update a param and revalidate
axdc
axdcOP•3y ago
okay sweet that's extremely essentially what I have now but with AshPhoenix.Form.update_form, which I suspect will stop my field values from vanishing on validation?
ZachDaniel
ZachDaniel•3y ago
Should do
axdc
axdcOP•3y ago
How is update_form different from set_data? I'm not really grokking it from the documentation. I'm trying to understand what I'm doing here because I keep running into things that feel inexplicable.
ZachDaniel
ZachDaniel•3y ago
Set data is for modifying the underlying record of the form. Update form allows you to pick any nested form in the structure and modify it in some way.
axdc
axdcOP•3y ago
Got it. I've gotten it working for the edit action and I'll be doing new next. I think it might be a bit of a monstrosity but I'm working my way through it 😅
axdc
axdcOP•3y ago
defmodule GorgonWeb.HuskLive.FormComponent do
use GorgonWeb, :live_component alias Gorgon.Forge.Husk @impl true def render(assigns) do ~H"""
<.header> <%= @title %> <:subtitle> {{copy}}

<.sim...
ZachDaniel
ZachDaniel•3y ago
usually the edit and the create can be the same form
axdc
axdcOP•3y ago
ok cool, I think it's just angry about changes I've made for this so now I've gotta make those work with the cases where things are empty because it's new 🙂
ZachDaniel
ZachDaniel•3y ago
We could probably have something like
# adding an item
AshPhoenix.Form.update_params(form_path, fn params ->
Map.update(params, "field", [""], &(&1 ++ [""]))
end)

#removing an item at index
AshPhoenix.Form.update_params(form_path, fn params ->
Map.update(params, "field", [], &List.delete_at(&1, index))
end)
# adding an item
AshPhoenix.Form.update_params(form_path, fn params ->
Map.update(params, "field", [""], &(&1 ++ [""]))
end)

#removing an item at index
AshPhoenix.Form.update_params(form_path, fn params ->
Map.update(params, "field", [], &List.delete_at(&1, index))
end)
to simplify this much more
axdc
axdcOP•3y ago
I'll give that a shot!! I am working hard to become more simple :thinkies:

Did you find this page helpful?