From ec3566eef4cd287c81944cf92bab2357ab9a5492 Mon Sep 17 00:00:00 2001 From: Gary Rennie Date: Thu, 16 Nov 2023 22:16:10 +0000 Subject: [PATCH] Push pending events before redirecting Previously, there was no way to handle both `push_event` and `push_redirect` occuring in the same callback. The redirect would prevent the events from being sent. This commit checks the diff for any new events, and if they exist, sends them over the channel. --- lib/phoenix_live_view/channel.ex | 8 +++++++ lib/phoenix_live_view/diff.ex | 7 ++++++ .../integrations/event_test.exs | 23 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/lib/phoenix_live_view/channel.ex b/lib/phoenix_live_view/channel.ex index ee919411aa..8286fdd99f 100644 --- a/lib/phoenix_live_view/channel.ex +++ b/lib/phoenix_live_view/channel.ex @@ -799,6 +799,7 @@ defmodule Phoenix.LiveView.Channel do |> Map.put(:to, to) new_state + |> push_pending_events_on_redirect(new_socket) |> push_redirect(opts, ref) |> stop_shutdown_redirect(:redirect, opts) @@ -806,6 +807,7 @@ defmodule Phoenix.LiveView.Channel do opts = copy_flash(new_state, flash, opts) new_state + |> push_pending_events_on_redirect(new_socket) |> push_redirect(opts, ref) |> stop_shutdown_redirect(:redirect, opts) @@ -813,6 +815,7 @@ defmodule Phoenix.LiveView.Channel do opts = copy_flash(new_state, flash, opts) new_state + |> push_pending_events_on_redirect(new_socket) |> push_live_redirect(opts, ref, pending_diff_ack) |> stop_shutdown_redirect(:live_redirect, opts) @@ -837,6 +840,11 @@ defmodule Phoenix.LiveView.Channel do end end + defp push_pending_events_on_redirect(state, socket) do + if diff = Diff.get_push_events_diff(socket), do: push_diff(state, diff, nil) + state + end + defp patch_params_and_action!(socket, %{to: to}) do destructure [path, query], :binary.split(to, ["?", "#"], [:global]) to = %{socket.host_uri | path: path, query: query} diff --git a/lib/phoenix_live_view/diff.ex b/lib/phoenix_live_view/diff.ex index 2a06ceee7d..a7d5921bfc 100644 --- a/lib/phoenix_live_view/diff.ex +++ b/lib/phoenix_live_view/diff.ex @@ -153,6 +153,13 @@ defmodule Phoenix.LiveView.Diff do end end + @doc """ + Returns a diff containing only the events that have been pushed. + """ + def get_push_events_diff(socket) do + if events = Utils.get_push_events(socket), do: %{@events => events} + end + defp maybe_put_title(diff, socket) do if Utils.changed?(socket.assigns, :page_title) do Map.put(diff, @title, socket.assigns.page_title) diff --git a/test/phoenix_live_view/integrations/event_test.exs b/test/phoenix_live_view/integrations/event_test.exs index 1631cbecaf..f19f0e6630 100644 --- a/test/phoenix_live_view/integrations/event_test.exs +++ b/test/phoenix_live_view/integrations/event_test.exs @@ -34,6 +34,29 @@ defmodule Phoenix.LiveView.EventTest do assert render(view) =~ "count: 123" end + test "supports events with redirects", %{conn: conn} do + {:ok, view, _html} = live(conn, "/events") + + GenServer.call( + view.pid, + {:run, + fn socket -> + new_socket = + socket + |> Component.assign(count: 123) + |> LiveView.push_event("my-event", %{one: 1}) + |> LiveView.push_event("my-event", %{one: 2}) + |> LiveView.push_redirect(to: "/events") + + {:reply, :ok, new_socket} + end} + ) + + assert_push_event(view, "my-event", %{one: 1}) + assert_push_event(view, "my-event", %{one: 2}) + assert_redirected(view, "/events") + end + test "sends updates with no assigns diff", %{conn: conn} do {:ok, view, _html} = live(conn, "/events")