I am working on creating a multi-page application form.
I have decided to hide the next-button until there is an answer for each question on the page.
To detect when an answer is updated, I have tried the following:
Attaching a phx-blur
to the inputs. This worked, but forced the user to exit the input, which wasnt intuitive enough in certain cases.
Attaching a phx-keyup
to inputs. I could not find a way to attach a reference to indicate which input was being edited, so I could update the relevant answer.
Wrapping the inputs in a <form>
with phx-change
. This triggered the event correctly, but did not reload the DOM. I even converted the navbar into a live_component
, and tried triggering a forced re-render with send_update/2
.
Do you have any ideas on how to handle this case?
Thanks in advance
This is the way to go. Can you share your live view / template (or a distilled version) so we can say what could be wrong? Thanks!
Hey @chrismccord appreciate your input
I created the following to replicate the issue:
defmodule GladosWeb.LiveView.Test do
use Phoenix.LiveView
def render(assigns) do
Phoenix.View.render(GladosWeb.MemberView, "test_application_page.html", assigns)
end
def mount(%{}, socket) do
socket =
socket
|> assign(:show_button, false)
|> assign(:answer, "")
{:ok, socket}
end
def handle_event(
"set_answer",
%{"_target" => [target]} = values,
socket
) do
answer = values[target]
socket
|> assign(:show_button, answer != "")
|> assign(:answer, answer)
{:noreply, socket}
end
end
<form phx-change="set_answer">
<input type="string" name="input" value="<%= @answer %>" class="border" %>
<br/>
Show button? <%= @show_button %>
</form>
When editing the answer, the socket is updated with the correct value for :show_button. However, this is not updated in the DOM.
outlog
January 16, 2020, 9:50am
4
socket
|> assign(:show_button, answer != "")
|> assign(:answer, answer)
{:noreply, socket}
seems like those assigns doesn’t go on the socket/reply eg you need
socket = socket
|> assign(:show_button, answer != "")
|> assign(:answer, answer)
{:noreply, socket}
this is a bit of OOP vs FP…
socket
|> assign(:show_button, answer != "")
|> assign(:answer, answer)
is basically a noop in FP - while in OOP it would most likely have mutated “socket”
1 Like
Oh wow yeah that was obvious. Thank you
1 Like
@outlog I stored the updated socket. That did not solve it unfortunately.
can you share your new code?
String input
The following code is when using phx-change
in conjunction with a input of type string
.
<form phx-change="set_answer">
<input type="string" name="input" value="<%= @answer %>" class="border" %>
<br/>
Show button? <%= @show_button %>
</form>
defmodule GladosWeb.LiveView.Test do
use Phoenix.LiveView
def render(assigns) do
Phoenix.View.render(GladosWeb.MemberView, "test_application_page.html", assigns)
end
def mount(%{}, socket) do
socket =
socket
|> assign(:show_button, false)
|> assign(:answer, "")
{:ok, socket}
end
def handle_event(
"set_answer",
%{"_target" => [target]} = values,
socket
) do
answer = values[target]
socket =
socket
|> assign(:show_button, answer != "")
|> assign(:answer, answer)
{:noreply, socket}
end
end
select input
defmodule GladosWeb.LiveView.Test do
use Phoenix.LiveView
def render(assigns) do
Phoenix.View.render(GladosWeb.MemberView, "test_application_page.html", assigns)
end
def mount(%{}, socket) do
socket =
socket
|> assign(:show_button, false)
|> assign(:answer, "hide")
{:ok, socket}
end
def handle_event(
"set_answer",
%{"_target" => [target]} = values,
socket
) do
answer = values[target]
socket =
socket
|> assign(:show_button, answer == "show")
|> assign(:answer, answer)
{:noreply, socket}
end
end
<form phx-change="set_answer">
<select name="select" class="mb-4">
<option <%= if @answer == "hide", do: "selected" %> value="hide">hide button</option>
<option <%= if @answer == "show", do: "selected" %> value="show">show button</option>
</select>
<br/>
Show button? <%= @show_button %>
</form>
sfusato
January 16, 2020, 10:45pm
9
I don’t think you are properly pattern matching in your handle_event
. If you do a print to the console inside the function, does it gets printed to the console?
If my suspicion is right, start with a bare values
in the function head, print that to the console, see the format and then refine your pattern matching.
Yes it does in fact call the function, @sfusato
outlog
January 17, 2020, 7:25pm
11
check your browser console - believe there is a bug in phoenix_live_view.js
InvalidCharacterError: The string contains invalid characters.
outlog
January 17, 2020, 8:09pm
12
ok, did the debugging…
error is the “%” at the end of your:
<input type=“string” name=“input” value="<%= @answer %>" class=“border” %>
that breaks phoenix_live_view.js - remove that and you are good to go…
btw type=“string” is not standard https://www.w3schools.com/tags/att_input_type.asp so maybe use “text”
Thank you, @outlog that fixed it
1 Like