Editable · Form
Phoenix Form
<.form for={@form} phx-submit="save_phoenix">
<.editable field={@form[:text]} placeholder="Enter text" activation_mode="dblclick" select_on_focus class="editable">
<:label>Text</:label>
<:edit_trigger><.heroicon name="hero-pencil-square" class="icon" /></:edit_trigger>
<:submit_trigger><.heroicon name="hero-check" class="icon" /></:submit_trigger>
<:cancel_trigger><.heroicon name="hero-x-mark" class="icon" /></:cancel_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.editable>
<.action type="submit" class="button button--accent">Submit</.action>
</.form>
defmodule MyAppWeb.EditableFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
phoenix_form =
Phoenix.Component.to_form(%{"text" => ""}, as: :editable_phoenix, id: "editable-live-form-phoenix")
{:ok, assign(socket, :phoenix_form, phoenix_form)}
end
def handle_event("save_phoenix", %{"editable_phoenix" => params}, socket) do
text = params["text"] || ""
{:noreply,
assign(
socket,
:phoenix_form,
Phoenix.Component.to_form(%{"text" => text}, as: :editable_phoenix, id: "editable-live-form-phoenix")
)}
end
end
Phoenix Form + Ecto
<.form for={@form} phx-change="validate" phx-submit="save">
<.editable field={@form[:text]} on_value_change="value_changed" placeholder="Enter text" activation_mode="dblclick" select_on_focus class="editable">
<:label>Text</:label>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
<:edit_trigger><.heroicon name="hero-pencil-square" class="icon" /></:edit_trigger>
<:submit_trigger><.heroicon name="hero-check" class="icon" /></:submit_trigger>
<:cancel_trigger><.heroicon name="hero-x-mark" class="icon" /></:cancel_trigger>
</.editable>
<.action type="submit" class="button button--accent">Submit</.action>
</.form>
defmodule MyAppWeb.EditableFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
ecto_form =
%MyApp.Form.EditableForm{}
|> MyApp.Form.EditableForm.changeset(%{})
|> Phoenix.Component.to_form(as: :editable_ecto, id: "editable-live-form-ecto")
{:ok, assign(socket, :ecto_form, ecto_form)}
end
def handle_event("validate", event_params, socket) do
params =
Map.get(event_params, "editable_ecto") ||
socket.assigns.ecto_form.params
changeset =
%MyApp.Form.EditableForm{}
|> MyApp.Form.EditableForm.changeset(params)
|> Map.put(:action, :validate)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset,
action: :validate,
as: :editable_ecto,
id: "editable-live-form-ecto"
)
)}
end
def handle_event("value_changed", %{"value" => value}, socket) do
params = Map.merge(socket.assigns.ecto_form.params || %{}, %{"text" => to_string(value)})
changeset =
%MyApp.Form.EditableForm{}
|> MyApp.Form.EditableForm.changeset(params)
|> Map.put(:action, :validate)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset,
action: :validate,
as: :editable_ecto,
id: "editable-live-form-ecto"
)
)}
end
def handle_event("save", event_params, socket) do
params =
Map.get(event_params, "editable_ecto") ||
socket.assigns.ecto_form.params
case MyApp.Form.EditableForm.changeset(%MyApp.Form.EditableForm{}, params) do
%Ecto.Changeset{valid?: true} = changeset ->
_data = Ecto.Changeset.apply_changes(changeset)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(
MyApp.Form.EditableForm.changeset(%MyApp.Form.EditableForm{}, params),
as: :editable_ecto,
id: "editable-live-form-ecto"
)
)}
changeset ->
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset,
action: :insert,
as: :editable_ecto,
id: "editable-live-form-ecto"
)
)}
end
end
end
defmodule MyApp.Form.EditableForm do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :text, :string
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:text])
|> validate_required([:text], message: "can't be blank")
end
end