إدخال HTML أصلي · النموذج
Phoenix
<.form
for={@form}
action={~p"/native-input/form"}
method="post"
id="native-input-form-phoenix"
class="flex flex-col gap-6 w-full max-w-md"
>
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<.form_full_fields variant={:ecto} id_prefix="native-input-phoenix" f={@form} />
<.action type="submit" id="native-input-form-phoenix-submit" class="button button--accent">
Submit
</.action>
</.form>
def native_input_form_page(conn, _params) do
phoenix_form =
Phoenix.Component.to_form(MyAppWeb.Demos.NativeInputDemo.phoenix_form_defaults(),
as: :profile_phoenix,
id: "native-input-form-phoenix"
)
render(conn, :native_input_form_page, phoenix_form: phoenix_form)
end
def native_input_form_submit(conn, %{"profile_phoenix" => profile}) do
conn
|> put_flash(:info, "Submitted: #{MyApp.Forms.NativeInputProfile.format_for_toast(profile)}")
|> redirect(to: ~p"/native-input/form#native-input-form-phoenix")
end
نموذج Phoenix (changeset)
<.form
for={@form}
action={~p"/native-input/form"}
method="post"
>
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Text</p>
<.native_input field={@form[:name]} type="text" placeholder="Your name" class="native-input">
<:label>Name</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:email]} type="email" placeholder="you@example.com" class="native-input">
<:label>Email</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:bio]} type="textarea" placeholder="Short bio" class="native-input">
<:label>Bio</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:website]} type="url" placeholder="https://example.com" class="native-input">
<:label>Website</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:phone]} type="tel" placeholder="+1 234 567 8900" class="native-input">
<:label>Phone</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:q]} type="search" placeholder="Search" class="native-input">
<:label>Search</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:count]} type="number" min={0} max={100} step={1} class="native-input">
<:label>Count</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:password]} type="password" class="native-input">
<:label>Password</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
</div>
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Date & time</p>
<.native_input field={@form[:birth_date]} type="date" class="native-input">
<:label>Birth date</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:datetime]} type="datetime-local" class="native-input">
<:label>Date and time</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:reminder_time]} type="time" class="native-input">
<:label>Reminder time</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:month]} type="month" class="native-input">
<:label>Month</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:week]} type="week" class="native-input">
<:label>Week</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
</div>
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Multiple</p>
<.native_input
field={@form[:tags]}
type="select"
multiple
options={[
"Elixir": "elixir",
Phoenix: "phoenix",
LiveView: "liveview",
Ecto: "ecto",
OTP: "otp"
]}
prompt="Choose tags..."
class="native-input"
>
<:label>Tags</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
</div>
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Other</p>
<.native_input field={@form[:color]} type="color" value="#3b82f6" class="native-input">
<:label>Color</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input
field={@form[:role]}
type="select"
options={[Admin: "admin", User: "user"]}
prompt="Choose role..."
class="native-input"
>
<:label>Role</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input
field={@form[:size]}
type="radio"
options={[Small: "s", Medium: "m", Large: "l"]}
class="native-input"
>
<:label>Size</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
<.native_input field={@form[:agree]} type="checkbox" class="native-input">
<:label>I agree</:label>
<:error :let={msg}>{msg}</:error>
</.native_input>
</div>
<.action type="submit" class="button button--accent">
Submit
</.action>
</.form>
def native_input_form_strict_create(conn, %{"profile_validate" => params}) do
case MyApp.Forms.NativeInputProfile.changeset_validate(%MyApp.Forms.NativeInputProfile{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
_data = Ecto.Changeset.apply_changes(changeset)
conn
|> put_flash(:info, "Saved profile (strict)")
|> redirect(to: "/native-input/form#native-input-form-validate")
changeset ->
changeset = Map.put(changeset, :action, :insert)
validate_form =
Phoenix.Component.to_form(changeset, as: :profile_validate, id: "native-input-validate-form")
form =
MyApp.Forms.NativeInputProfile.changeset(%MyApp.Forms.NativeInputProfile{}, %{})
|> Phoenix.Component.to_form(as: :profile_changeset, id: "native-input-changeset-form")
render(conn, :native_input_form_page, form: form, validate_form: validate_form)
end
end
defmodule MyApp.Forms.NativeInputProfile do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :name, :string
field :email, :string
field :bio, :string
field :birth_date, :string
field :datetime, :string
field :reminder_time, :string
field :month, :string
field :week, :string
field :website, :string
field :phone, :string
field :q, :string
field :color, :string
field :count, :integer
field :password, :string
field :role, :string
field :tags, {:array, :string}, default: []
field :size, :string
field :agree, :boolean, default: false
end
def changeset(profile, attrs \\ %{}) do
profile
|> cast(attrs, [:name, :email, :bio, :birth_date, :datetime, :reminder_time, :month, :week, :website, :phone, :q, :color, :count, :password, :role, :tags, :size, :agree])
|> validate_required([:name, :email, :agree])
|> validate_acceptance(:agree)
end
def changeset_validate(profile, attrs \\ %{}) do
profile
|> cast(attrs, [:name, :email, :bio, :birth_date, :datetime, :reminder_time, :month, :week, :website, :phone, :q, :color, :count, :password, :role, :tags, :size, :agree])
|> validate_required([:name, :email, :bio, :birth_date, :datetime, :reminder_time, :month, :week, :website, :phone, :q, :color, :count, :password, :role, :tags, :size, :agree], message: "can't be blank")
|> validate_format(:email, ~r/@/, message: "must look like an email address")
|> validate_length(:bio, min: 3, message: "must be at least 3 characters")
|> validate_length(:password, min: 6, message: "must be at least 6 characters")
|> validate_format(:website, ~r/^https?:\\/\\//, message: "must start with http:// or https://")
|> validate_number(:count, greater_than: 0, less_than: 99, message: "must be between 1 and 98")
|> validate_change(:tags, fn :tags, tags ->
if is_list(tags) and tags != [], do: [], else: [tags: "can't be blank"]
end)
|> validate_acceptance(:agree, message: "must be accepted to continue")
end
end
Native HTML Form
<form action={~p"/native-input/form"} method="post">
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Text</p>
<.native_input type="text" name="profile[name]" placeholder="Your name" class="native-input">
<:label>Name</:label>
</.native_input>
<.native_input type="email" name="profile[email]" placeholder="you@example.com" class="native-input">
<:label>Email</:label>
</.native_input>
<.native_input type="textarea" name="profile[bio]" placeholder="Short bio" class="native-input">
<:label>Bio</:label>
</.native_input>
<.native_input type="url" name="profile[website]" placeholder="https://example.com" class="native-input">
<:label>Website</:label>
</.native_input>
<.native_input type="tel" name="profile[phone]" placeholder="+1 234 567 8900" class="native-input">
<:label>Phone</:label>
</.native_input>
<.native_input type="search" name="profile[q]" placeholder="Search" class="native-input">
<:label>Search</:label>
</.native_input>
<.native_input type="number" name="profile[count]" min={0} max={100} step={1} class="native-input">
<:label>Count</:label>
</.native_input>
<.native_input type="password" name="profile[password]" class="native-input">
<:label>Password</:label>
</.native_input>
</div>
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Date & time</p>
<.native_input type="date" name="profile[birth_date]" class="native-input">
<:label>Birth date</:label>
</.native_input>
<.native_input type="datetime-local" name="profile[datetime]" class="native-input">
<:label>Date and time</:label>
</.native_input>
<.native_input type="time" name="profile[reminder_time]" class="native-input">
<:label>Reminder time</:label>
</.native_input>
<.native_input type="month" name="profile[month]" class="native-input">
<:label>Month</:label>
</.native_input>
<.native_input type="week" name="profile[week]" class="native-input">
<:label>Week</:label>
</.native_input>
</div>
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Multiple</p>
<.native_input
type="select"
multiple
name="profile[tags][]"
options={[
"Elixir": "elixir",
Phoenix: "phoenix",
LiveView: "liveview",
Ecto: "ecto",
OTP: "otp"
]}
prompt="Choose tags..."
class="native-input"
>
<:label>Tags</:label>
</.native_input>
</div>
<div class="flex flex-col gap-3">
<p class="typo typo--sm font-medium">Other</p>
<.native_input type="color" name="profile[color]" value="#3b82f6" class="native-input">
<:label>Color</:label>
</.native_input>
<.native_input type="select" name="profile[role]" options={[Admin: "admin", User: "user"]} prompt="Choose role..." class="native-input">
<:label>Role</:label>
</.native_input>
<.native_input type="radio" name="profile[size]" options={[Small: "s", Medium: "m", Large: "l"]} class="native-input">
<:label>Size</:label>
</.native_input>
<.native_input type="checkbox" name="profile[agree]" class="native-input">
<:label>I agree</:label>
</.native_input>
</div>
<.action type="submit" class="button button--accent">
Submit
</.action>
</form>
def native_input_form_submit(conn, %{"profile" => profile}) do
conn
|> put_flash(:info, "Submitted: profile=#{inspect(profile)}")
|> redirect(to: ~p"/native-input/form#native-input-form-native")
end