Packages
corex
0.1.0-alpha.16
0.1.2
0.1.1
0.1.0
0.1.0-rc.1
0.1.0-rc.0
0.1.0-beta.5
0.1.0-beta.4
0.1.0-beta.3
0.1.0-beta.2
0.1.0-beta.1
0.1.0-alpha.33
0.1.0-alpha.32
0.1.0-alpha.31
0.1.0-alpha.30
0.1.0-alpha.29
0.1.0-alpha.28
0.1.0-alpha.27
0.1.0-alpha.26
0.1.0-alpha.25
0.1.0-alpha.24
0.1.0-alpha.23
0.1.0-alpha.22
0.1.0-alpha.21
0.1.0-alpha.20
0.1.0-alpha.19
0.1.0-alpha.18
0.1.0-alpha.17
0.1.0-alpha.16
0.1.0-alpha.15
0.1.0-alpha.14
0.1.0-alpha.13
0.1.0-alpha.12
0.1.0-alpha.11
0.1.0-alpha.10
0.1.0-alpha.9
0.1.0-alpha.8
0.1.0-alpha.7
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
Accessible and unstyled UI components library written in Elixir and TypeScript that integrates Zag.js state machines into the Phoenix Framework.
Current section
Files
Jump to
Current section
Files
lib/form.ex
defmodule Corex.Form do
@moduledoc ~S'''
Helper functions to work with forms.
Corex form components such as `Corex.Checkbox` and `Corex.Select` with classic form and with Phoenix form using the `Phoenix.Component.form/1` function.
## Examples
### Classic Form
In a classic form, you can use the `name` attribute to identify the checkbox.
The generated parameters will be as follows: `/?terms=true`
This works in Controller View and Live View
```heex
<form id="my-form">
<.checkbox name="terms" class="checkbox">
<:label>I accept the terms</:label>
</.checkbox>
<button type="submit">Submit</button>
</form>
```
### Phoenix Form
When using with Phoenix forms, you must add an id to the form using the `Corex.Form.get_form_id/1` function.
### Controller
```elixir
defmodule MyAppWeb.PageController do
use MyAppWeb, :controller
def home(conn, params) do
form = Phoenix.Component.to_form(Map.get(params, "user", %{}), as: :user)
render(conn, :home, form: form)
end
end
```
```heex
<.form :let={f} as={:user} for={@form} id={get_form_id(@form)} method="get">
<.checkbox field={f[:terms]} class="checkbox">
<:label>I accept the terms</:label>
<:error :let={msg}>
<.icon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.checkbox>
<button type="submit">Submit</button>
</.form>
```
#### In a Live View
You must use the `Corex.Form.get_form_id/1` function to get the form id and pass it to the form component.
```elixir
defmodule MyAppWeb.CheckboxLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
form = to_form(%{"terms" => "false"}, as: :user)
{:ok, socket |> assign(:form, form)}
end
def render(assigns) do
~H"""
<.form as={:user} for={@form} id={get_form_id(@form)}>
<.checkbox field={@form[:terms]} class="checkbox">
<:label>I accept the terms</:label>
<:error :let={msg}>
<.icon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.checkbox>
<button type="submit">Submit</button>
</.form>
"""
end
end
```
### With Ecto changeset
When using Ecto changeset for validation and inside a Live view you must enable the controlled mode.
This allows the Live View to be the source of truth and the component to be in sync accordingly
First lets create an embededed schema and changeset
```elixir
defmodule MyApp.Account.User do
use Ecto.Schema
import Ecto.Changeset
alias MyApp.Account.User
embedded_schema do
field :term, :boolean, default: false
end
@doc false
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:term])
|> validate_required([:term])
|> validate_acceptance(:terms)
end
end
```
```elixir
defmodule MyAppWeb.UserLive do
use MyAppWeb, :live_view
alias MyApp.Account.User
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :form, to_form(User.changeset(%User{}, %{})))}
end
@impl true
def handle_event("validate", %{"user" => user_params}, socket) do
changeset = User.changeset(%User{}, user_params)
{:noreply, assign(socket, form: to_form(changeset, action: :validate))}
end
@impl true
def render(assigns) do
~H"""
<.form for={@form} id={get_form_id(@form)} phx-change="validate">
<.checkbox field={@form[:terms]} class="checkbox" controlled>
<:label>I accept the terms</:label>
<:error :let={msg}>
<.icon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.checkbox>
</.form>
"""
end
end
```
'''
alias Phoenix.Component
alias Phoenix.HTML.Form
alias Ecto.Changeset
@doc """
Returns the form id.
Accepts either:
* an `Ecto.Changeset`
* a `Phoenix.HTML.Form`
## Examples
#### In a Controller
```heex
<.form :let={f} for={@changeset} id={get_form_id(@changeset)}>
<.checkbox field={f[:terms]} class="checkbox">
<:label>I accept the terms</:label>
</.checkbox>
<button type="submit">Submit</button>
</.form>
```
#### In a Live View
```heex
<.form for={@form} id={get_form_id(@form)}>
<.checkbox field={@form[:terms]} controlled class="checkbox">
<:label>I accept the terms</:label>
</.checkbox>
<button type="submit">Submit</button>
</.form>
```
"""
@spec get_form_id(Form.t() | Changeset.t()) :: binary()
def get_form_id(%Form{id: id}) when is_binary(id), do: id
def get_form_id(%Changeset{} = changeset) do
changeset
|> Component.to_form()
|> Map.fetch!(:id)
end
def get_form_id(other) do
raise ArgumentError,
"expected Ecto.Changeset or Phoenix.HTML.Form, got: #{inspect(other)}"
end
end