tl;dr: I want to know the most phoenix way of letting users fill a {:array, :string}
input via live view form component.
defp deps do
[
{:argon2_elixir, "~> 2.0"},
{:phoenix, "~> 1.6.0"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.16.0"},
]
end
I’m currently experimenting with the current schema and the relevant prop is :synonyms
with {:array, :string}
type. The user should be able to write any amount of items there.
defmodule MyApp.MyContext.Tag do
use Ecto.Schema
import Ecto.Changeset
schema "tags" do
field :synonyms, {:array, :string}
timestamps()
end
@doc false
def changeset(tag, attrs) do
tag
|> cast(attrs, [:synonyms])
end
end
I was able to make both edit and create work with some assignments called @synonyms
and dynamically rendering inputs called name="tag[synonyms][]"
using the code below:
defmodule MyAppWeb.TagLive.FormComponent do
use MyAppWeb, :live_component
alias MyApp.MyContext
@impl true
def update(%{tag: tag} = assigns, socket) do
changeset = MyContext.change_tag(tag)
{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)
|> assign(:synonyms, tag.synonyms)} # <---- relevant
end
@impl true
def handle_event("validate", %{"tag" => tag_params}, socket) do # <---- no changes needed
# tag_params => %{ "synonyms: ["foo", "bar"], rest... }, which is ok :)
changeset =
socket.assigns.tag
|> Jobs.change_tag(tag_params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :changeset, changeset)}
end
# unrelated ...
end
<.form
let={f}
for={@changeset}
id="tag-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save">
<%= label f, :slug %>
<%= text_input f, :slug %>
<%= error_tag f, :slug %>
<%= label f, :type %>
<%= select f, :type, Ecto.Enum.values(MyApp.MyContext.Tag, :type), prompt: "Choose a value" %>
<%= error_tag f, :type %>
<%= for s <- @synonyms do %> <---------------- here
<%= label f, :slug %>
<input name="tag[synonyms][]" value={s}>
<%= error_tag f, :slug %>
<% end %>
<div>
<%= submit "Save", phx_disable_with: "Saving..." %>
</div>
</.form>
From there I should also make “add more” and “remove” inputs which is fine but I was left wondering if I’ve missed something obvious on the docs or somewhere else that I wasn’t able to find by my searches (as most results seem to deal with embedded schemas instead of an array on the very own schema)