I have a phoenix live view resource, which contains some text fields.
The resource was created by phx.gen.live and the form is essentially default out of the box, the echo schema looks like this:
defmodule UpTally.Services.Tsl do
use Ecto.Schema
import Ecto.Changeset
schema "tsl" do
field :interface, EctoFields.IP
field :ip, EctoFields.IP
field :name, :string
field :port, :integer
field :tsl_version, Ecto.Enum, values: [:tsl_v3, :tsl_v5]
field :send_interval, :integer
field :tsl_offset, :integer
field :polling_interval, :integer
field :polling_enabled, :boolean
timestamps()
end
@doc false
def changeset(tsl, attrs) do
tsl
|> cast(attrs, [
:name,
:ip,
:port,
:interface,
:tsl_version,
:send_interval,
:tsl_offset,
:polling_interval,
:polling_enabled
])
|> validate_required([
:name,
:ip,
:port,
:interface,
:tsl_version,
:send_interval,
:tsl_offset,
:polling_interval,
:polling_enabled
])
|> validate_if_ip(:interface)
end
defp validate_if_ip(changeset, field) when is_atom(field) do
validate_change(changeset, field, fn field, value ->
case UpTally.Interfaces.is_valid?(value) do
true ->
[]
false ->
[{field, "Is not a valid local interface address."}]
end
end)
end
end
If I click to edit one of the items, triggering the modal to be displayed, and then highlight some of the text in one of the form fields the modal closes. It happens every time, consistently.
Any idea what is causing this, or something I can change to stop it
Here is the form:
defmodule UpTallyWeb.TslLive.FormComponent do
use UpTallyWeb, :live_component
alias UpTally.Services
@impl true
def render(assigns) do
~H"""
<div>
<.header>
<%= @title %>
</.header>
<.simple_form
for={@form}
id="tsl-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input field={@form[:name]} type="text" label="Name" />
<.input field={@form[:ip]} type="text" label="TSL Transmit IP" />
<.input field={@form[:port]} type="number" label="TSL Transmit Port" />
<.input field={@form[:tsl_offset]} type="number" label="TSL ID Offset" />
<.input field={@form[:interface]} type="text" label="Local Interface IP" />
<.input
field={@form[:tsl_version]}
type="select"
label="Tsl Protocol version"
options={get_tsl_options()}
/>
<:actions>
<.button phx-disable-with="Saving...">Save Tsl</.button>
</:actions>
<.input
field={@form[:send_interval]}
type="number"
label="TSL Send delay between each message"
/>
<.input field={@form[:polling_enabled]} type="checkbox" label="Enable TSL polling send" />
<.input field={@form[:polling_interval]} type="number" label="Polling interval" />
</.simple_form>
</div>
"""
end
@impl true
def update(%{tsl: tsl, action: action} = assigns, socket) when action == :edit do
changeset = Services.change_update_tsl(tsl)
{:ok,
socket
|> assign(assigns)
|> assign_form(changeset)}
end
@impl true
def update(%{tsl: tsl} = assigns, socket) do
changeset = Services.change_tsl(tsl)
{:ok,
socket
|> assign(assigns)
|> assign_form(changeset)}
end
@impl true
def handle_event("validate", %{"tsl" => tsl_params}, socket) do
changeset =
socket.assigns.tsl
|> Services.change_tsl(tsl_params)
|> Map.put(:action, :validate)
{:noreply, assign_form(socket, changeset)}
end
def handle_event("save", %{"tsl" => tsl_params}, socket) do
save_tsl(socket, socket.assigns.action, tsl_params)
end
defp save_tsl(socket, :edit, tsl_params) do
case Services.update_tsl(socket.assigns.tsl, tsl_params) do
{:ok, tsl} ->
notify_parent({:saved, tsl})
{:noreply,
socket
|> put_flash(:info, "Tsl updated successfully")
|> push_patch(to: socket.assigns.patch)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}
end
end
defp save_tsl(socket, :new, tsl_params) do
case Services.create_tsl(tsl_params) do
{:ok, tsl} ->
notify_parent({:saved, tsl})
{:noreply,
socket
|> put_flash(:info, "Tsl created successfully")
|> push_patch(to: socket.assigns.patch)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}
end
end
defp assign_form(socket, %Ecto.Changeset{} = changeset) do
assign(socket, :form, to_form(changeset))
end
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
defp get_tsl_options() do
[{"TSL v3.1", :tsl_v3}, {"TSL v5", :tsl_v5}]
end
end
Here’s a link to a video of the behaviour:
https://drive.google.com/file/d/1bbL3PWfRf7oMfIz8G2pAXk5OwdcSuPfz/view?usp=sharing
Thanks!