Skip to content

Commit 001cbcb

Browse files
authored
Merge pull request #132 from hernanat/afh-fixy
fix out-of-bounds active_option crash
2 parents a06e76c + 99a7bc0 commit 001cbcb

2 files changed

Lines changed: 77 additions & 2 deletions

File tree

lib/live_select/component.ex

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ defmodule LiveSelect.Component do
149149
|> assign_new(opt, fn -> default end)
150150
end)
151151
|> update(:options, &normalize_options/1)
152+
|> then(fn socket ->
153+
if Map.has_key?(assigns, :options) &&
154+
socket.assigns.active_option >= length(socket.assigns.options) do
155+
assign(socket, active_option: -1)
156+
else
157+
socket
158+
end
159+
end)
152160
|> assign(:text_input_field, String.to_atom("#{socket.assigns.field.field}_text_input"))
153161

154162
socket =
@@ -312,9 +320,18 @@ defmodule LiveSelect.Component do
312320

313321
@impl true
314322
def handle_event("option_click", %{"idx" => idx}, socket) do
315-
socket = assign(socket, :active_option, String.to_integer(idx))
323+
idx = String.to_integer(idx)
316324

317-
{:noreply, maybe_select(socket)}
325+
socket =
326+
if idx >= 0 && idx < length(socket.assigns.options) do
327+
socket
328+
|> assign(:active_option, idx)
329+
|> maybe_select()
330+
else
331+
socket
332+
end
333+
334+
{:noreply, socket}
318335
end
319336

320337
@impl true

test/live_select_test.exs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,4 +1155,62 @@ defmodule LiveSelectTest do
11551155

11561156
assert_selected_static(live, "B")
11571157
end
1158+
1159+
test "resets active_option when options shrink via send_update", %{conn: conn} do
1160+
stub_options([%{label: "A", value: 1}, %{label: "B", value: 2}, %{label: "C", value: 3}])
1161+
1162+
{:ok, live, _html} = live(conn, "/")
1163+
1164+
type(live, "ABC")
1165+
1166+
navigate(live, 3, :down)
1167+
1168+
send_update(live, options: [%{label: "X", value: 10}, %{label: "Y", value: 20}])
1169+
1170+
keydown(live, "Enter")
1171+
1172+
refute_selected(live)
1173+
end
1174+
1175+
test "does not crash when pressing Enter with out-of-bounds active_option", %{conn: conn} do
1176+
stub_options([%{label: "A", value: 1}, %{label: "B", value: 2}, %{label: "C", value: 3}])
1177+
1178+
{:ok, live, _html} = live(conn, "/")
1179+
1180+
type(live, "ABC")
1181+
1182+
navigate(live, 5, :down)
1183+
1184+
send_update(live, options: [%{label: "X", value: 10}, %{label: "Y", value: 20}])
1185+
1186+
keydown(live, "Enter")
1187+
1188+
refute_selected(live)
1189+
end
1190+
1191+
test "ignores out-of-bounds idx in option_click event", %{conn: conn} do
1192+
stub_options([%{label: "A", value: 1}, %{label: "B", value: 2}, %{label: "C", value: 3}])
1193+
1194+
{:ok, live, _html} = live(conn, "/")
1195+
1196+
type(live, "ABC")
1197+
1198+
element(live, selectors()[:container])
1199+
|> render_hook("option_click", %{idx: "999"})
1200+
1201+
refute_selected(live)
1202+
end
1203+
1204+
test "ignores negative idx in option_click event", %{conn: conn} do
1205+
stub_options([%{label: "A", value: 1}, %{label: "B", value: 2}, %{label: "C", value: 3}])
1206+
1207+
{:ok, live, _html} = live(conn, "/")
1208+
1209+
type(live, "ABC")
1210+
1211+
element(live, selectors()[:container])
1212+
|> render_hook("option_click", %{idx: "-1"})
1213+
1214+
refute_selected(live)
1215+
end
11581216
end

0 commit comments

Comments
 (0)