Phoenix Form · Single
<.form
for={@form}
action={~p"/date-picker/form"}
method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.date_picker
field={@form[:date]}
translation={%Corex.DatePicker.Translation{open_calendar: "Select date", close_calendar: "Select date", input: "Select date"}}
class="date-picker"
>
<:label>Date</:label>
<:trigger>
<.heroicon name="hero-calendar" class="icon" />
</:trigger>
<:prev_trigger>
<.heroicon name="hero-chevron-left" class="icon" />
</:prev_trigger>
<:next_trigger>
<.heroicon name="hero-chevron-right" class="icon" />
</:next_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def date_picker_form_page(conn, _params) do
phoenix_form =
Phoenix.Component.to_form(%{"date" => ""}, as: :date_picker_phoenix, id: "date-picker-form-phoenix")
render(conn, :date_picker_form_page, phoenix_form: phoenix_form)
end
def date_picker_form_submit(conn, params) do
if is_map(params["date_picker_phoenix"]) do
date = params["date_picker_phoenix"]["date"] || ""
conn
|> put_flash(:info, "Submitted: date=#{date}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-phoenix")
end
end
Phoenix Form · Multiple
<.form for={@form} action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.date_picker
field={@form[:dates]}
selection_mode="multiple"
max_selected_dates={3}
translation={%Corex.DatePicker.Translation{open_calendar: "Select dates", close_calendar: "Select dates", input: "Dates"}}
class="date-picker"
>
<:label>Dates</:label>
<:trigger><.heroicon name="hero-calendar" class="icon" /></:trigger>
<:prev_trigger><.heroicon name="hero-chevron-left" class="icon" /></:prev_trigger>
<:next_trigger><.heroicon name="hero-chevron-right" class="icon" /></:next_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def date_picker_form_page(conn, _params) do
phoenix_multiple_form =
Phoenix.Component.to_form(%{"dates" => []},
as: :date_picker_phoenix_multiple,
id: "date-picker-form-phoenix-multiple"
)
render(conn, :date_picker_form_page, phoenix_multiple_form: phoenix_multiple_form)
end
def date_picker_form_submit(conn, %{"date_picker_phoenix_multiple" => %{"dates" => dates}}) do
conn
|> put_flash(:info, "Submitted: dates=#{Corex.DatePicker.format_value("multiple", dates)}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-phoenix-multiple")
end
Phoenix Form · Range
<.form for={@form} action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.date_picker
field={@form[:date_range]}
selection_mode="range"
translation={%Corex.DatePicker.Translation{open_calendar: "Select date range", close_calendar: "Select date range", input: "Date range", range_start: "From", range_end: "To"}}
class="date-picker"
>
<:label>Date range</:label>
<:trigger><.heroicon name="hero-calendar" class="icon" /></:trigger>
<:prev_trigger><.heroicon name="hero-chevron-left" class="icon" /></:prev_trigger>
<:next_trigger><.heroicon name="hero-chevron-right" class="icon" /></:next_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def date_picker_form_page(conn, _params) do
phoenix_range_form =
Phoenix.Component.to_form(%{"date_range" => []},
as: :date_picker_phoenix_range,
id: "date-picker-form-phoenix-range"
)
render(conn, :date_picker_form_page, phoenix_range_form: phoenix_range_form)
end
def date_picker_form_submit(conn, %{"date_picker_phoenix_range" => params}) do
date_range = Corex.DatePicker.format_value("range", Map.get(params, "date_range", []))
conn
|> put_flash(:info, "Submitted: date_range=#{date_range}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-phoenix-range")
end
Phoenix Form + Ecto · Single
<.form
for={@form}
action={~p"/date-picker/form"}
method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.date_picker
field={@form[:date]}
translation={%Corex.DatePicker.Translation{open_calendar: "Select date", close_calendar: "Select date", input: "Select date"}}
class="date-picker"
>
<:label>Date (required)</:label>
<:trigger>
<.heroicon name="hero-calendar" class="icon" />
</:trigger>
<:prev_trigger>
<.heroicon name="hero-chevron-left" class="icon" />
</:prev_trigger>
<:next_trigger>
<.heroicon name="hero-chevron-right" class="icon" />
</:next_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def date_picker_form_page(conn, _params) do
form =
%MyApp.Form.DatePickerForm{}
|> MyApp.Form.DatePickerForm.changeset_validate(%{})
|> Phoenix.Component.to_form(as: :date_picker_validate, id: "date-picker-validate-form")
render(conn, :date_picker_form_page, form: form)
end
def date_picker_form_submit(conn, params) do
if is_map(params["date_picker_validate"]) do
case MyApp.Form.DatePickerForm.changeset_validate(%MyApp.Form.DatePickerForm{}, params["date_picker_validate"]) do
%Ecto.Changeset{valid?: true} = changeset ->
data = Ecto.Changeset.apply_changes(changeset)
conn
|> put_flash(:info, "Submitted: date=#{Corex.DatePicker.format_value("single", data.date)}")
|> redirect(to: ~p"/date-picker/form#date-picker-validate-form")
changeset ->
changeset = Map.put(changeset, :action, :insert)
form = Phoenix.Component.to_form(changeset, as: :date_picker_validate, id: "date-picker-validate-form")
render(conn, :date_picker_form_page, form: form)
end
end
end
defmodule MyApp.Form.DatePickerForm do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :date, :date
field :dates, {:array, :date}
field :date_range, {:array, :date}
end
def changeset(form, attrs \\ %{}) do
form
|> cast(normalize_range_attrs(attrs), [:date, :dates, :date_range])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:date])
|> validate_required([:date], message: "can't be blank")
end
def changeset_validate_dates(form, attrs \\ %{}) do
form
|> cast(attrs, [:dates])
|> validate_required([:dates], message: "can't be blank")
|> validate_length(:dates, min: 1, message: "can't be blank")
end
def changeset_validate_range(form, attrs \\ %{}) do
form
|> cast(normalize_range_attrs(attrs), [:date_range])
|> validate_required([:date_range], message: "can't be blank")
|> validate_length(:date_range, min: 2, max: 2, message: "must be a start and end date")
end
defp normalize_range_attrs(%{"date_range" => range} = attrs) when is_binary(range) do
%{attrs | "date_range" => String.split(range, ",", trim: true)}
end
defp normalize_range_attrs(attrs), do: attrs
end
Phoenix Form + Ecto · Multiple
<.form for={@form} action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.date_picker
field={@form[:dates]}
selection_mode="multiple"
max_selected_dates={3}
translation={%Corex.DatePicker.Translation{open_calendar: "Select dates", close_calendar: "Select dates", input: "Dates"}}
class="date-picker"
>
<:label>Dates</:label>
<:trigger><.heroicon name="hero-calendar" class="icon" /></:trigger>
<:prev_trigger><.heroicon name="hero-chevron-left" class="icon" /></:prev_trigger>
<:next_trigger><.heroicon name="hero-chevron-right" class="icon" /></:next_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def date_picker_form_page(conn, _params) do
ecto_multiple_form =
%MyApp.Form.DatePickerForm{}
|> MyApp.Form.DatePickerForm.changeset_validate_dates(%{})
|> Phoenix.Component.to_form(as: :date_picker_ecto_multiple, id: "date-picker-form-ecto-multiple")
render(conn, :date_picker_form_page, ecto_multiple_form: ecto_multiple_form)
end
def date_picker_form_submit(conn, %{"date_picker_ecto_multiple" => params}) do
params = Corex.DatePicker.cast_params("multiple", params)
case MyApp.Form.DatePickerForm.changeset_validate_dates(%MyApp.Form.DatePickerForm{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
data = Ecto.Changeset.apply_changes(changeset)
conn
|> put_flash(:info, "Submitted: dates=#{Corex.DatePicker.format_value("multiple", data.dates)}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-ecto-multiple")
changeset ->
changeset = Map.put(changeset, :action, :insert)
form =
Phoenix.Component.to_form(changeset,
as: :date_picker_ecto_multiple,
id: "date-picker-form-ecto-multiple"
)
render(conn, :date_picker_form_page, ecto_multiple_form: form)
end
end
Phoenix Form + Ecto · Range
<.form for={@form} action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.date_picker
field={@form[:date_range]}
selection_mode="range"
translation={%Corex.DatePicker.Translation{open_calendar: "Select date range", close_calendar: "Select date range", input: "Date range", range_start: "From", range_end: "To"}}
class="date-picker"
>
<:label>Date range</:label>
<:trigger><.heroicon name="hero-calendar" class="icon" /></:trigger>
<:prev_trigger><.heroicon name="hero-chevron-left" class="icon" /></:prev_trigger>
<:next_trigger><.heroicon name="hero-chevron-right" class="icon" /></:next_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def date_picker_form_page(conn, _params) do
ecto_range_form =
%MyApp.Form.DatePickerForm{}
|> MyApp.Form.DatePickerForm.changeset_validate_range(%{})
|> Phoenix.Component.to_form(as: :date_picker_ecto_range, id: "date-picker-form-ecto-range")
render(conn, :date_picker_form_page, ecto_range_form: ecto_range_form)
end
def date_picker_form_submit(conn, %{"date_picker_ecto_range" => params}) do
params = Corex.DatePicker.cast_params("range", params)
case MyApp.Form.DatePickerForm.changeset_validate_range(%MyApp.Form.DatePickerForm{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
data = Ecto.Changeset.apply_changes(changeset)
conn
|> put_flash(:info, "Submitted: date_range=#{Corex.DatePicker.format_value("range", data.date_range)}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-ecto-range")
changeset ->
changeset = Map.put(changeset, :action, :insert)
form =
Phoenix.Component.to_form(changeset,
as: :date_picker_ecto_range,
id: "date-picker-form-ecto-range"
)
render(conn, :date_picker_form_page, ecto_range_form: form)
end
end
Native HTML Form · Single
<form action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<.date_picker
name="date_picker_form[date]"
translation={%Corex.DatePicker.Translation{open_calendar: "Select date", close_calendar: "Select date", input: "Select date"}}
class="date-picker"
>
<:label>Date</:label>
<:trigger>
<.heroicon name="hero-calendar" class="icon" />
</:trigger>
<:prev_trigger>
<.heroicon name="hero-chevron-left" class="icon" />
</:prev_trigger>
<:next_trigger>
<.heroicon name="hero-chevron-right" class="icon" />
</:next_trigger>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</form>
def date_picker_form_submit(conn, %{"date_picker_form" => %{"date" => date}}) do
conn
|> put_flash(:info, "Submitted: date=#{date}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-native")
end
Native HTML Form · Multiple
<form action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<.date_picker
name="date_picker_form_multiple[dates]"
selection_mode="multiple"
max_selected_dates={3}
translation={%Corex.DatePicker.Translation{open_calendar: "Select dates", close_calendar: "Select dates", input: "Dates"}}
class="date-picker"
>
<:label>Dates</:label>
<:trigger><.heroicon name="hero-calendar" class="icon" /></:trigger>
<:prev_trigger><.heroicon name="hero-chevron-left" class="icon" /></:prev_trigger>
<:next_trigger><.heroicon name="hero-chevron-right" class="icon" /></:next_trigger>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</form>
def date_picker_form_submit(conn, %{"date_picker_form_multiple" => %{"dates" => dates}}) do
dates = List.wrap(dates) |> Enum.join(", ")
conn
|> put_flash(:info, "Submitted: dates=#{dates}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-native-multiple")
end
Native HTML Form · Range
<form action={~p"/date-picker/form"} method="post"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<.date_picker
name="date_picker_form_range[date_range]"
selection_mode="range"
translation={%Corex.DatePicker.Translation{open_calendar: "Select date range", close_calendar: "Select date range", input: "Date range", range_start: "From", range_end: "To"}}
class="date-picker"
>
<:label>Date range</:label>
<:trigger><.heroicon name="hero-calendar" class="icon" /></:trigger>
<:prev_trigger><.heroicon name="hero-chevron-left" class="icon" /></:prev_trigger>
<:next_trigger><.heroicon name="hero-chevron-right" class="icon" /></:next_trigger>
</.date_picker>
<.action type="submit" class="button ui-accent">Submit</.action>
</form>
def date_picker_form_submit(conn, %{"date_picker_form_range" => params}) do
date_range = Corex.DatePicker.format_value("range", Map.get(params, "date_range", []))
conn
|> put_flash(:info, "Submitted: date_range=#{date_range}")
|> redirect(to: ~p"/date-picker/form#date-picker-form-native-range")
end