<.form
for={@form}
action={~p"/tags-input/form"}
method="post"
>
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<.tags_input field={@form[:tags]} class="tags-input">
<:label>Keywords</:label>
<:close><.heroicon name="hero-x-mark" /></:close>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" />
{msg}
</:error>
</.tags_input>
<.action type="submit" class="button button--accent">
Submit
</.action>
</.form>
def tags_input_form_page(conn, _params) do
form =
MyApp.Forms.TagsInputForm.changeset_validate(%MyApp.Forms.TagsInputForm{}, %{"tags" => ["alpha", "beta"]})
|> Phoenix.Component.to_form(as: :tags_input_changeset, id: "tags-input-changeset-form")
render(conn, :tags_input_form_page, form: form)
end
def tags_input_form_create(conn, %{"tags_input_changeset" => params}) do
case MyApp.Forms.TagsInputForm.changeset_validate(%MyApp.Forms.TagsInputForm{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
data = Ecto.Changeset.apply_changes(changeset)
conn
|> put_flash(:info, "Submitted: tags=#{data.tags}")
|> redirect(to: ~p"/tags-input/form#tags-input-changeset-form")
changeset ->
changeset = Map.put(changeset, :action, :insert)
form =
Phoenix.Component.to_form(changeset,
as: :tags_input_changeset,
id: "tags-input-changeset-form"
)
render(conn, :tags_input_form_page, form: form)
end
end
defmodule MyApp.Forms.TagsInputForm do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :tags, {:array, :string}
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:tags])
|> validate_required([:tags])
|> validate_tag_count(:tags, 3)
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:tags])
|> validate_required([:tags], message: "can't be blank")
|> validate_tag_list(:tags, 3)
end
defp validate_tag_count(changeset, field, max) do
validate_change(changeset, field, fn _, value ->
n = if is_list(value), do: length(value), else: 0
if n <= max, do: [], else: [{field, "must have at most #{max} tags"}]
end)
end
defp validate_tag_list(changeset, field, max) do
validate_change(changeset, field, fn _, value ->
cond do
not is_list(value) -> [{field, "is invalid"}]
length(value) > max -> [{field, "must have at most #{max} tags"}]
Enum.any?(value, &String.contains?(&1, ";")) -> [{field, "must not contain semicolons"}]
true -> []
end
end)
end
end