在 phx-change 之后更新表单字段的值
Update the value of a form field after phx-change
我有一个 LiveView 应用程序可以搜索机场代码。当用户输入 ham
时,它应该用 HAM
(String.upcase/1) 替换该表单字段的内容,但事实并非如此。但根据我对我的代码的理解,它应该。我必须更改什么才能用大写版本替换该字段中的所有输入?
顺便说一句:如果我向它添加一个按钮并使用 phx-submit
而不是 phx-change
,它就会起作用。但我想让它为 phx-change
工作。
设置
$ mix phx.new travelagent --live --no-ecto
$ cd travelagent
lib/travelagent_web/router.ex
[...]
scope "/", TravelagentWeb do
pipe_through :browser
live "/", PageLive, :index
live "/search", SearchLive
end
[...]
lib/travelagent/airports.ex
defmodule Travelagent.Airports do
def search_by_code(""), do: []
def search_by_code(code) do
list_airports()
|> Enum.filter(&String.starts_with?(&1.code, code))
end
def list_airports do
[
%{name: "Berlin Brandenburg", code: "BER"},
%{name: "Berlin Schönefeld", code: "SXF"},
%{name: "Berlin Tegel", code: "TXL"},
%{name: "Bremen", code: "BRE"},
%{name: "Köln/Bonn", code: "CGN"},
%{name: "Dortmund", code: "DTM"},
%{name: "Dresden", code: "DRS"},
%{name: "Düsseldorf", code: "DUS"},
%{name: "Frankfurt", code: "FRA"},
%{name: "Frankfurt-Hahn", code: "HHN"},
%{name: "Hamburg", code: "HAM"},
%{name: "Hannover", code: "HAJ"},
%{name: "Leipzig Halle", code: "LEJ"},
%{name: "München", code: "MUC"},
%{name: "Münster Osnabrück", code: "FMO"},
%{name: "Nürnberg", code: "NUE"},
%{name: "Paderborn Lippstadt", code: "PAD"},
%{name: "Stuttgart", code: "STR"}
]
end
end
lib/travelagent_web/live/search_live.ex
defmodule TravelagentWeb.SearchLive do
use TravelagentWeb, :live_view
alias Travelagent.Airports
def mount(_params, _session, socket) do
socket =
socket
|> assign(:airport_code, "")
|> assign(:airports, [])
{:ok, socket}
end
def handle_event(
"airport_code_search",
%{"airport_code" => airport_code},
socket
) do
airport_code = String.upcase(airport_code)
socket =
socket
|> assign(:airport_code, airport_code)
|> assign(:airports, Airports.search_by_code(airport_code))
{:noreply, socket}
end
end
lib/travelagent_web/live/search_live.html.leex
<form phx-change="airport_code_search">
<fieldset>
<label for="nameField">Airport Code</label>
<input type="text" name="airport_code" value="<%= @airport_code %>"
placeholder="e.g. FRA"
autofocus autocomplete="off" />
</fieldset>
</form>
<%= unless @airports == [] do %>
<h2>Search Results</h2>
<table>
<thead>
<tr>
<th>Airport Code</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<%= for airport <- @airports do %>
<tr>
<td><%= airport.code %></td>
<td><%= airport.name %></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
JavaScript 控制台输出
phx提交版本
如果我使用这种形式:
<form phx-submit="airport_code_search">
<fieldset>
<label for="nameField">Airport Code</label>
<input type="text" name="airport_code" value="<%= @airport_code %>"
placeholder="e.g. FRA"
autofocus autocomplete="off" />
<input class="button-primary" type="submit" value="Search Airport">
</fieldset>
</form>
我得到了这个工作结果(输入 fra
并单击按钮后):
PS:JavaScript 或 CSS 这个问题有上百万种可能的解决方案。但我想知道如何使用 LiveView 正确解决这个问题。
The JavaScript client is always the source of truth for current input values. For any given input with focus, LiveView will never overwrite the input's current value, even if it deviates from the server's rendered updates.
这种情况下的解决方案是使用 JS hooks.
我有一个 LiveView 应用程序可以搜索机场代码。当用户输入 ham
时,它应该用 HAM
(String.upcase/1) 替换该表单字段的内容,但事实并非如此。但根据我对我的代码的理解,它应该。我必须更改什么才能用大写版本替换该字段中的所有输入?
顺便说一句:如果我向它添加一个按钮并使用 phx-submit
而不是 phx-change
,它就会起作用。但我想让它为 phx-change
工作。
设置
$ mix phx.new travelagent --live --no-ecto
$ cd travelagent
lib/travelagent_web/router.ex
[...]
scope "/", TravelagentWeb do
pipe_through :browser
live "/", PageLive, :index
live "/search", SearchLive
end
[...]
lib/travelagent/airports.ex
defmodule Travelagent.Airports do
def search_by_code(""), do: []
def search_by_code(code) do
list_airports()
|> Enum.filter(&String.starts_with?(&1.code, code))
end
def list_airports do
[
%{name: "Berlin Brandenburg", code: "BER"},
%{name: "Berlin Schönefeld", code: "SXF"},
%{name: "Berlin Tegel", code: "TXL"},
%{name: "Bremen", code: "BRE"},
%{name: "Köln/Bonn", code: "CGN"},
%{name: "Dortmund", code: "DTM"},
%{name: "Dresden", code: "DRS"},
%{name: "Düsseldorf", code: "DUS"},
%{name: "Frankfurt", code: "FRA"},
%{name: "Frankfurt-Hahn", code: "HHN"},
%{name: "Hamburg", code: "HAM"},
%{name: "Hannover", code: "HAJ"},
%{name: "Leipzig Halle", code: "LEJ"},
%{name: "München", code: "MUC"},
%{name: "Münster Osnabrück", code: "FMO"},
%{name: "Nürnberg", code: "NUE"},
%{name: "Paderborn Lippstadt", code: "PAD"},
%{name: "Stuttgart", code: "STR"}
]
end
end
lib/travelagent_web/live/search_live.ex
defmodule TravelagentWeb.SearchLive do
use TravelagentWeb, :live_view
alias Travelagent.Airports
def mount(_params, _session, socket) do
socket =
socket
|> assign(:airport_code, "")
|> assign(:airports, [])
{:ok, socket}
end
def handle_event(
"airport_code_search",
%{"airport_code" => airport_code},
socket
) do
airport_code = String.upcase(airport_code)
socket =
socket
|> assign(:airport_code, airport_code)
|> assign(:airports, Airports.search_by_code(airport_code))
{:noreply, socket}
end
end
lib/travelagent_web/live/search_live.html.leex
<form phx-change="airport_code_search">
<fieldset>
<label for="nameField">Airport Code</label>
<input type="text" name="airport_code" value="<%= @airport_code %>"
placeholder="e.g. FRA"
autofocus autocomplete="off" />
</fieldset>
</form>
<%= unless @airports == [] do %>
<h2>Search Results</h2>
<table>
<thead>
<tr>
<th>Airport Code</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<%= for airport <- @airports do %>
<tr>
<td><%= airport.code %></td>
<td><%= airport.name %></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
JavaScript 控制台输出
phx提交版本
如果我使用这种形式:
<form phx-submit="airport_code_search">
<fieldset>
<label for="nameField">Airport Code</label>
<input type="text" name="airport_code" value="<%= @airport_code %>"
placeholder="e.g. FRA"
autofocus autocomplete="off" />
<input class="button-primary" type="submit" value="Search Airport">
</fieldset>
</form>
我得到了这个工作结果(输入 fra
并单击按钮后):
PS:JavaScript 或 CSS 这个问题有上百万种可能的解决方案。但我想知道如何使用 LiveView 正确解决这个问题。
The JavaScript client is always the source of truth for current input values. For any given input with focus, LiveView will never overwrite the input's current value, even if it deviates from the server's rendered updates.
这种情况下的解决方案是使用 JS hooks.