Phoenix Form
<.form for={@form} phx-submit="save_phoenix"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.slider
field={@form[:volume]}
markers marker_values={[0, 25, 50, 75, 100]}
class="slider"
>
<:label>Volume</:label>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.slider>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
defmodule MyAppWeb.SliderFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
phoenix_form =
Phoenix.Component.to_form(%{"volume" => "0"}, as: :slider_phoenix, id: "slider-live-form-phoenix")
{:ok, assign(socket, :phoenix_form, phoenix_form)}
end
def handle_event("save_phoenix", %{"slider_phoenix" => params}, socket) do
volume = params["volume"] || ""
{:noreply,
assign(
socket,
:phoenix_form,
Phoenix.Component.to_form(%{"volume" => volume}, as: :slider_phoenix, id: "slider-live-form-phoenix")
)}
end
end
Phoenix Form · Range
<.form for={@form} phx-submit="save_phoenix_range" class="flex flex-col gap-space-lg w-full max-w-xl">
<.slider
field={@form[:volume]}
value={[20, 80]}
min_steps_between_thumbs={1}
markers marker_values={[0, 25, 50, 75, 100]}
class="slider"
>
<:label>Volume</:label>
</.slider>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def mount(_params, _session, socket) do
phoenix_range_form =
Phoenix.Component.to_form(%{"volume" => ["20", "80"]},
as: :slider_phoenix_range,
id: "slider-live-form-phoenix-range"
)
{:ok, assign(socket, :phoenix_range_form, phoenix_range_form)}
end
def handle_event("save_phoenix_range", %{"slider_phoenix_range" => params}, socket) do
volume = params["volume"] || []
{:noreply,
assign(
socket,
:phoenix_range_form,
Phoenix.Component.to_form(%{"volume" => volume},
as: :slider_phoenix_range,
id: "slider-live-form-phoenix-range"
)
)}
end
Phoenix Form + Ecto
<.form
for={@form}
phx-change="validate_volume"
phx-submit="save_volume"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.slider
field={@form[:volume]}
markers marker_values={[0, 25, 50, 75, 100]}
class="slider"
>
<:label>Volume (over 90)</:label>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.slider>
<.action type="submit" class="button ui-accent">Submit</:action>
</.form>
defmodule MyAppWeb.SliderFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
ecto_form =
%MyApp.Forms.Slider{}
|> MyApp.Forms.Slider.changeset_validate(%{})
|> Phoenix.Component.to_form(as: :slider_ecto, id: "slider-live-form-ecto")
{:ok, assign(socket, :ecto_form, ecto_form)}
end
def handle_event("validate", %{"slider_ecto" => params}, socket) do
changeset =
%MyApp.Forms.Slider{}
|> MyApp.Forms.Slider.changeset_validate(params)
|> Map.put(:action, :validate)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset,
action: :validate,
as: :slider_ecto,
id: "slider-live-form-ecto"
)
)}
end
def handle_event("save", %{"slider_ecto" => params}, socket) do
case MyApp.Forms.Slider.changeset_validate(%MyApp.Forms.Slider{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
_data = Ecto.Changeset.apply_changes(changeset)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(
MyApp.Forms.Slider.changeset_validate(%MyApp.Forms.Slider{}, params),
as: :slider_ecto,
id: "slider-live-form-ecto"
)
)}
changeset ->
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset,
action: :insert,
as: :slider_ecto,
id: "slider-live-form-ecto"
)
)}
end
end
end
defmodule MyApp.Forms.Slider do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :volume, :float
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
|> validate_number(:volume,
greater_than: 90.0,
message: "must be over 90"
)
end
end
Phoenix Form + Ecto · Range
<.form
for={@form}
phx-change="validate_volume_range"
phx-submit="save_volume_range"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.slider
field={@form[:volume]}
value={[20, 80]}
min_steps_between_thumbs={1}
markers marker_values={[0, 25, 50, 75, 100]}
class="slider"
>
<:label>Volume (high over 90)</:label>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.slider>
<.action type="submit" class="button ui-accent">Submit</:action>
</.form>
def mount(_params, _session, socket) do
changeset =
MyApp.Forms.SliderRange.changeset_validate(%MyApp.Forms.SliderRange{}, %{})
{:ok,
assign(socket, :form,
Phoenix.Component.to_form(changeset,
as: :slider_validated_range,
id: "live-product-volume-validated-range-form"
)
)}
end
def handle_event("validate_volume_range", %{"slider_validated_range" => params}, socket) do
changeset =
%MyApp.Forms.SliderRange{}
|> MyApp.Forms.SliderRange.changeset_validate(params)
|> Map.put(:action, :validate)
{:noreply,
assign(socket, :form,
Phoenix.Component.to_form(changeset,
action: :validate,
as: :slider_validated_range,
id: "live-product-volume-validated-range-form"
)
)}
end
def handle_event("save_volume_range", %{"slider_validated_range" => params}, socket) do
case MyApp.Forms.SliderRange.changeset_validate(%MyApp.Forms.SliderRange{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
{:noreply,
assign(socket, :form,
Phoenix.Component.to_form(changeset,
as: :slider_validated_range,
id: "live-product-volume-validated-range-form"
)
)}
changeset ->
{:noreply,
assign(socket, :form,
Phoenix.Component.to_form(changeset,
action: :insert,
as: :slider_validated_range,
id: "live-product-volume-validated-range-form"
)
)}
end
end
defmodule MyApp.Forms.SliderRange do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :volume, {:array, :float}
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
|> validate_length(:volume, is: 2, message: "must have two values")
|> validate_high_over_90()
end
defp validate_high_over_90(changeset) do
case get_field(changeset, :volume) do
[_, high] when is_number(high) and high > 90 ->
changeset
[_, _high] ->
add_error(changeset, :volume, "must be over 90")
_ ->
changeset
end
end
end
Phoenix Form + Ecto + Invalid
<.form for={@validate_invalid_form} phx-change="validate_invalid" phx-submit="save_invalid"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.slider
id="slider-live-form-validate-invalid-volume"
field={@validate_invalid_form[:volume]}
value={@validate_invalid_volume_value}
markers marker_values={[0, 25, 50, 75, 100]}
invalid={Corex.FormField.invalid?(@validate_invalid_form[:volume])}
class="slider"
>
<:label>Volume (over 90)</:label>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.slider>
<.action type="submit" id="slider-live-form-validate-invalid-submit" class="button ui-accent">
Submit
</.action>
</.form>
defmodule MyAppWeb.SliderFormLive do
use MyAppWeb, :live_view
def handle_event("validate_invalid", params, socket) do
validate_ecto_invalid(socket, Map.get(params, "slider_validate_invalid", %{}))
end
def handle_event("save_invalid", params, socket) do
save_ecto_invalid(socket, Map.get(params, "slider_validate_invalid", %{}))
end
end
defmodule MyApp.Forms.Slider do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :volume, :float
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
|> validate_number(:volume,
greater_than: 90.0,
message: "must be over 90"
)
end
end
Phoenix Form + Ecto + Invalid · Range
<.form for={@form} phx-change="validate_invalid_range" phx-submit="save_invalid_range"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.slider
field={@form[:volume]}
value={[20, 80]}
min_steps_between_thumbs={1}
markers marker_values={[0, 25, 50, 75, 100]}
invalid={Corex.FormField.invalid?(@form[:volume])}
class="slider"
>
<:label>Volume (high over 90)</:label>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.slider>
<.action type="submit" class="button ui-accent">Submit</.action>
</.form>
def handle_event("validate_invalid_range", params, socket) do
validate_ecto_invalid_range(socket, Map.get(params, "slider_validate_invalid_range", %{}))
end
def handle_event("save_invalid_range", params, socket) do
save_ecto_invalid_range(socket, Map.get(params, "slider_validate_invalid_range", %{}))
end
defmodule MyApp.Forms.SliderRange do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :volume, {:array, :float}
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:volume])
|> validate_required([:volume])
|> validate_length(:volume, is: 2, message: "must have two values")
|> validate_high_over_90()
end
defp validate_high_over_90(changeset) do
case get_field(changeset, :volume) do
[_, high] when is_number(high) and high > 90 ->
changeset
[_, _high] ->
add_error(changeset, :volume, "must be over 90")
_ ->
changeset
end
end
end