11if Code . ensure_loaded? ( Phoenix.HTML ) && Code . ensure_loaded? ( Phoenix.HTML.Form ) &&
22 Code . ensure_loaded? ( PhoenixHTMLHelpers.Form ) do
33 defmodule PolymorphicEmbed.HTML.Form do
4- @ moduledoc """
5- Defines functions for using PolymorphicEmbed with `Phoenix.HTML.Form`.
6- """
74 import Phoenix.HTML , only: [ html_escape: 1 ]
8- import Phoenix.HTML.Form , only: [ input_value: 2 ]
95 import PhoenixHTMLHelpers.Form , only: [ hidden_inputs_for: 1 ]
106
11- @ doc """
12- Returns the polymorphic type of the given field in the given form data.
13- """
14- def get_polymorphic_type ( % Phoenix.HTML.Form { } = form , field ) do
15- % schema { } = form . source . data
16- get_polymorphic_type ( form , schema , field )
17- end
18-
19- def get_polymorphic_type ( % Phoenix.HTML.Form { } = form , schema , field ) do
20- case input_value ( form , field ) do
21- % Ecto.Changeset { data: value } ->
22- PolymorphicEmbed . get_polymorphic_type ( schema , field , value )
23-
24- % _ { } = value ->
25- PolymorphicEmbed . get_polymorphic_type ( schema , field , value )
26-
27- % { } = map ->
28- case PolymorphicEmbed . get_polymorphic_module ( schema , field , map ) do
29- nil ->
30- nil
31-
32- module ->
33- PolymorphicEmbed . get_polymorphic_type ( schema , field , module )
34- end
7+ defdelegate get_polymorphic_type ( form , field ) , to: PolymorphicEmbed.HTML.Helpers
358
36- list when is_list ( list ) ->
37- raise "Cannot infer the polymorphic type as the list of embeds may contain multiple types"
38-
39- nil ->
40- nil
41- end
42- end
9+ defdelegate to_form ( source_changeset , form , field , options ) ,
10+ to: PolymorphicEmbed.HTML.Helpers
4311
4412 @ doc """
4513 Generates a new form builder without an anonymous function.
@@ -62,15 +30,14 @@ if Code.ensure_loaded?(Phoenix.HTML) && Code.ensure_loaded?(Phoenix.HTML.Form) &
6230 <%= for channel_form <- polymorphic_embed_inputs_for f, :channel do %>
6331 <%= hidden_inputs_for(channel_form) %>
6432
65- <%= case get_polymorphic_type(f , Reminder, :channel) do %>
33+ <%= case get_polymorphic_type(reminder_form , Reminder, :channel) do %>
6634 <% :sms -> %>
6735 <%= label channel_form, :number %>
6836 <%= text_input channel_form, :number %>
6937
7038 <% :email -> %>
71- <%= label channel_form, :email_address %>
72- <%= text_input channel_form, :address %>
73- <% end %>
39+ <%= label channel_form, :email %>
40+ <%= text_input channel_form, :email %>
7441 <% end %>
7542 </.form>
7643 """
@@ -95,8 +62,8 @@ if Code.ensure_loaded?(Phoenix.HTML) && Code.ensure_loaded?(Phoenix.HTML.Form) &
9562 <%= text_input poly_form, :number %>
9663
9764 <% :email -> %>
98- <%= label poly_form, :email_address %>
99- <%= text_input poly_form, :address %>
65+ <%= label poly_form, :email %>
66+ <%= text_input poly_form, :email %>
10067 <% end %>
10168 <% end %>
10269 <% end %>
@@ -133,79 +100,5 @@ if Code.ensure_loaded?(Phoenix.HTML) && Code.ensure_loaded?(Phoenix.HTML.Form) &
133100 end )
134101 )
135102 end
136-
137- def to_form ( % { action: parent_action } = source_changeset , form , field , options ) do
138- id = to_string ( form . id <> "_#{ field } " )
139- name = to_string ( form . name <> "[#{ field } ]" )
140-
141- params = Map . get ( source_changeset . params || % { } , to_string ( field ) , % { } ) |> List . wrap ( )
142-
143- struct = Ecto.Changeset . apply_changes ( source_changeset )
144-
145- list_data =
146- case Map . get ( struct , field ) do
147- nil ->
148- type = Keyword . get ( options , :polymorphic_type , get_polymorphic_type ( form , field ) )
149- module = PolymorphicEmbed . get_polymorphic_module ( struct . __struct__ , field , type )
150- if module , do: [ struct ( module ) ] , else: [ ]
151-
152- data ->
153- List . wrap ( data )
154- end
155-
156- list_data
157- |> Enum . with_index ( )
158- |> Enum . map ( fn { data , i } ->
159- params = Enum . at ( params , i ) || % { }
160-
161- changeset =
162- data
163- |> Ecto.Changeset . change ( )
164- |> apply_action ( parent_action )
165-
166- errors = get_errors ( changeset )
167-
168- changeset = % Ecto.Changeset {
169- changeset
170- | action: parent_action ,
171- params: params ,
172- errors: errors ,
173- valid?: errors == [ ]
174- }
175-
176- % schema { } = source_changeset . data
177-
178- field_opts = PolymorphicEmbed . get_field_opts ( schema , field )
179- type_field_atom = Map . get ( field_opts , :type_field_atom , :__type__ )
180- # correctly set id and name for embeds_many inputs
181- array? = Map . get ( field_opts , :array? , false )
182-
183- index_string = Integer . to_string ( i )
184-
185- type = PolymorphicEmbed . get_polymorphic_type ( schema , field , changeset . data )
186-
187- % Phoenix.HTML.Form {
188- source: changeset ,
189- impl: Phoenix.HTML.FormData.Ecto.Changeset ,
190- id: if ( array? , do: id <> "_" <> index_string , else: id ) ,
191- name: if ( array? , do: name <> "[" <> index_string <> "]" , else: name ) ,
192- index: if ( array? , do: i ) ,
193- errors: errors ,
194- data: data ,
195- params: params ,
196- hidden: [ { type_field_atom , to_string ( type ) } ] ,
197- options: options
198- }
199- end )
200- end
201-
202- # If the parent changeset had no action, we need to remove the action
203- # from children changeset so we ignore all errors accordingly.
204- defp apply_action ( changeset , nil ) , do: % { changeset | action: nil }
205- defp apply_action ( changeset , _action ) , do: changeset
206-
207- defp get_errors ( % { action: nil } ) , do: [ ]
208- defp get_errors ( % { action: :ignore } ) , do: [ ]
209- defp get_errors ( % { errors: errors } ) , do: errors
210103 end
211104end
0 commit comments