Skip to content

Commit 3df1e6c

Browse files
authored
Accept function in Phoenix.Component.assign/2 (#4051)
1 parent f4344b4 commit 3df1e6c

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

lib/phoenix_component.ex

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1433,12 +1433,15 @@ defmodule Phoenix.Component do
14331433
14341434
The first argument is either a LiveView `socket` or an `assigns` map from function components.
14351435
1436-
A keyword list or a map of assigns must be given as argument to be merged into existing assigns.
1436+
When a keyword list or map is provided as the second argument, it will be merged into the existing assigns.
1437+
If a function is given, it takes the current assigns as an argument and its return
1438+
value will be merged into the current assigns.
14371439
14381440
## Examples
14391441
14401442
iex> assign(socket, name: "Elixir", logo: "💧")
14411443
iex> assign(socket, %{name: "Elixir"})
1444+
iex> assign(socket, fn %{name: name, logo: logo} -> %{title: Enum.join([name, logo], " | ")} end)
14421445
14431446
"""
14441447
def assign(socket_or_assigns, keyword_or_map)
@@ -1448,6 +1451,16 @@ defmodule Phoenix.Component do
14481451
end)
14491452
end
14501453

1454+
def assign(socket_or_assigns, fun) when is_function(fun, 1) do
1455+
assigns =
1456+
case socket_or_assigns do
1457+
%Socket{assigns: assigns} -> assigns
1458+
assigns -> assigns
1459+
end
1460+
1461+
assign(socket_or_assigns, fun.(assigns))
1462+
end
1463+
14511464
defp validate_assign_key!(:flash) do
14521465
raise ArgumentError,
14531466
":flash is a reserved assign by LiveView and it cannot be set directly. " <>

test/phoenix_component_test.exs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ defmodule Phoenix.ComponentUnitTest do
6767
assert socket.assigns.existing == [:foo, :bam]
6868
assert socket.assigns.__changed__.existing == [:foo, :bar]
6969
end
70+
71+
test "allows functions" do
72+
socket = assign(@socket, fn _ -> [existing: [:foo, :bar]] end)
73+
socket = Utils.clear_changed(socket)
74+
75+
socket = assign(socket, fn %{existing: [:foo, :bar]} -> %{existing: [:foo, :baz]} end)
76+
assert socket.assigns.existing == [:foo, :baz]
77+
assert socket.assigns.__changed__.existing == [:foo, :bar]
78+
end
7079
end
7180

7281
describe "assign with assigns" do
@@ -104,6 +113,16 @@ defmodule Phoenix.ComponentUnitTest do
104113
assert assigns.map == %{foo: :baz}
105114
assert assigns.__changed__ == nil
106115
end
116+
117+
test "allows functions" do
118+
assigns = assign(@assigns_changes, fn _ -> %{map: %{foo: :baz}} end)
119+
assert assigns.map == %{foo: :baz}
120+
assert assigns.__changed__[:map] == %{foo: :bar}
121+
122+
assigns = assign(@assigns_nil_changes, fn _ -> [map: %{foo: :baz}] end)
123+
assert assigns.map == %{foo: :baz}
124+
assert assigns.__changed__ == nil
125+
end
107126
end
108127

109128
describe "assign_new with socket" do

0 commit comments

Comments
 (0)