|
| 1 | +defmodule PhoenixTest.WebApp.MailingList do |
| 2 | + @moduledoc false |
| 3 | + use Ecto.Schema |
| 4 | + |
| 5 | + import Ecto.Changeset |
| 6 | + |
| 7 | + embedded_schema do |
| 8 | + field(:title, :string) |
| 9 | + |
| 10 | + embeds_many :emails, Email, on_replace: :delete do |
| 11 | + field(:email, :string) |
| 12 | + end |
| 13 | + end |
| 14 | + |
| 15 | + def changeset(list, attrs) do |
| 16 | + list |
| 17 | + |> cast(attrs, [:title]) |
| 18 | + |> cast_embed(:emails, |
| 19 | + with: &email_changeset/2, |
| 20 | + sort_param: :emails_sort, |
| 21 | + drop_param: :emails_drop |
| 22 | + ) |
| 23 | + end |
| 24 | + |
| 25 | + def email_changeset(email_notification, attrs) do |
| 26 | + cast(email_notification, attrs, [:email]) |
| 27 | + end |
| 28 | +end |
| 29 | + |
| 30 | +defmodule PhoenixTest.WebApp.OrdinalInputsLive do |
| 31 | + @moduledoc false |
| 32 | + use Phoenix.LiveView |
| 33 | + use Phoenix.Component |
| 34 | + |
| 35 | + import PhoenixTest.WebApp.Components |
| 36 | + |
| 37 | + alias PhoenixTest.WebApp.MailingList |
| 38 | + |
| 39 | + def mount(_params, _session, socket) do |
| 40 | + changeset = MailingList.changeset(%MailingList{}, %{}) |
| 41 | + |
| 42 | + {:ok, |
| 43 | + assign(socket, |
| 44 | + changeset: changeset, |
| 45 | + form: to_form(changeset), |
| 46 | + submitted: false, |
| 47 | + emails: [] |
| 48 | + )} |
| 49 | + end |
| 50 | + |
| 51 | + def render(assigns) do |
| 52 | + ~H""" |
| 53 | + <.form for={@form} phx-change="validate" phx-submit="submit"> |
| 54 | + <.input field={@form[:title]} label="Title" /> |
| 55 | + <.inputs_for :let={ef} field={@form[:emails]}> |
| 56 | + <input type="hidden" name="mailing_list[emails_sort][]" value={ef.index} /> |
| 57 | + <.input label="Email" type="text" field={ef[:email]} placeholder="email" /> |
| 58 | + <a class="underline" phx-click="remove-email" phx-value-index={ef.index}> |
| 59 | + Remove |
| 60 | + </a> |
| 61 | + </.inputs_for> |
| 62 | +
|
| 63 | + <input type="hidden" name="mailing_list[emails_drop][]" /> |
| 64 | +
|
| 65 | + <button phx-click="add-email">Add Email</button> |
| 66 | + <button type="submit">Submit</button> |
| 67 | + </.form> |
| 68 | +
|
| 69 | + <div> |
| 70 | + <%= if @submitted do %> |
| 71 | + <h3>Submitted Values:</h3> |
| 72 | + <div>Title: {@form.params["title"]}</div> |
| 73 | + <%= for email <- @emails do %> |
| 74 | + <div data-role="email">{email}</div> |
| 75 | + <% end %> |
| 76 | + <% end %> |
| 77 | + </div> |
| 78 | + """ |
| 79 | + end |
| 80 | + |
| 81 | + def handle_event("validate", %{"mailing_list" => params}, socket) do |
| 82 | + changeset = MailingList.changeset(%MailingList{}, params) |
| 83 | + {:noreply, assign(socket, changeset: changeset, form: to_form(changeset))} |
| 84 | + end |
| 85 | + |
| 86 | + def handle_event("add-email", _params, socket) do |
| 87 | + changeset = socket.assigns.changeset |
| 88 | + |
| 89 | + new_emails = |
| 90 | + Ecto.Changeset.get_field(changeset, :emails) ++ [%MailingList.Email{}] |
| 91 | + |
| 92 | + updated_changeset = |
| 93 | + MailingList.changeset(%{changeset.data | emails: new_emails}, %{}) |
| 94 | + |
| 95 | + {:noreply, assign(socket, changeset: updated_changeset, form: to_form(updated_changeset))} |
| 96 | + end |
| 97 | + |
| 98 | + def handle_event("remove-email", %{"index" => index}, socket) do |
| 99 | + index = String.to_integer(index) |
| 100 | + current_emails = Ecto.Changeset.get_field(socket.assigns.changeset, :emails) |
| 101 | + |
| 102 | + new_emails = List.delete_at(current_emails, index) |
| 103 | + |
| 104 | + updated_changeset = |
| 105 | + MailingList.changeset(%{socket.assigns.changeset.data | emails: new_emails}, %{}) |
| 106 | + |
| 107 | + {:noreply, assign(socket, changeset: updated_changeset, form: to_form(updated_changeset))} |
| 108 | + end |
| 109 | + |
| 110 | + def handle_event("submit", %{"mailing_list" => params}, socket) do |
| 111 | + changeset = MailingList.changeset(%MailingList{}, params) |
| 112 | + |
| 113 | + emails = |
| 114 | + changeset |
| 115 | + |> Ecto.Changeset.get_field(:emails) |
| 116 | + |> Enum.map(fn email -> email.email end) |
| 117 | + |> Enum.reject(&is_nil/1) |
| 118 | + |
| 119 | + {:noreply, |
| 120 | + assign(socket, |
| 121 | + changeset: changeset, |
| 122 | + form: to_form(changeset), |
| 123 | + submitted: true, |
| 124 | + emails: emails |
| 125 | + )} |
| 126 | + end |
| 127 | +end |
0 commit comments