Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream reset doesn't work when changing record filter #2895

Closed
cheerfulstoic opened this issue Oct 30, 2023 · 10 comments · Fixed by #2969
Closed

Stream reset doesn't work when changing record filter #2895

cheerfulstoic opened this issue Oct 30, 2023 · 10 comments · Fixed by #2969

Comments

@cheerfulstoic
Copy link

cheerfulstoic commented Oct 30, 2023

Environment

  • Elixir version (elixir -v): Elixir 1.14.5 (compiled with Erlang/OTP 25)
  • Phoenix version (mix deps): 1.7.9
  • Phoenix LiveView version (mix deps): 0.20.1
  • Operating system: MacOS 13.5.1
  • Browsers you attempted to reproduce this bug on (the more the merrier): Safari
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Actual behavior

I created this app to reproduce the issue: https://github.com/cheerfulstoic/live_view_reset_reproduction

It's using infinite scrolling. I start off with no records and two empty checkboxes. Each time the checkboxes are changed, reset: true is given. When checking one checkbox the correct records appear. When checking the second checkbox the original records aren't replaced with the new ones (showing records intermixed), but they are instead appended to the end of the list.

The issue isn't there using phoenix_live_view version 0.19.5

Expected behavior

Records should refresh instead of appending.


Following up from this comment: #2826 (comment)

@moomerman
Copy link

moomerman commented Nov 3, 2023

I can confirm I have the same issue here. My case is a stream of events with event filters. When I load the page all the events are rendered. When I click a filter, which removes some events from the stream it works as expected. But when I remove the filter I expect the list to return to the previous state, but it appends the events that have re-appeared to the bottom of the list instead of in the position they are in the stream. I'm using reset: true when the filters are added and removed.

Main [@dfcdb18] also doesn't work for me and can also confirm that it behaves as expected in LV 0.19.5.

@ffloyd
Copy link

ffloyd commented Nov 3, 2023

I have the exactly same situation @moomerman described. Tried use master branch - did not help.

@razmigh
Copy link

razmigh commented Nov 8, 2023

Same here, also created an isolated case using a simple table with numbers.
https://github.com/razmigh/lv-stream-test
commit 8518512

@SteffenDE
Copy link
Collaborator

SteffenDE commented Nov 29, 2023

Yep, seeing the same issue as @moomerman using the latest main.

I have a table with a list of elements like this [a, b, c, d] that gets reset on the server to [e, a, f, g] (so the first element of the initial list is now at the second position), but LiveView renders the list as [a, e, f, g] instead.

This still works for me, as suggested in #2864: 549d3b1

@csokun
Copy link
Contributor

csokun commented Dec 21, 2023

Feel like a race condition somewhere. Anyway I solved my problem by defer sending new results

...
def apply_action(socket, :index, params) do
   Process.send_after(self(), {:list, params}, 100);
   
   # clear existing items
   socket |> stream(:items, [], reset: true) 
end
...

def handle_info({:list, params}, socket) do
  # perform search/filtering
  new_items = [....]
  {:noreply, socket |> stream(:items, new_items)}
end

@josevalim
Copy link
Member

It isn't a race condition since everything is serialized, probably just an issue with the order of the operations!

@prsn-uk
Copy link
Contributor

prsn-uk commented Dec 24, 2023

@moomerman Updating to release 0.20.2 (2023-12-18) should fix this problem.

@SteffenDE
Copy link
Collaborator

@prsn-uk I cannot confirm this. I’ve been running with the GitHub main branch for a while and 0.20.2 does not fix the problem. Undoing the changes as I’ve described above indeed does fix this, although it probably reverts what should fix #2657.

SteffenDE pushed a commit to SteffenDE/phoenix_live_view that referenced this issue Dec 28, 2023
SteffenDE pushed a commit to SteffenDE/phoenix_live_view that referenced this issue Dec 29, 2023
chrismccord pushed a commit that referenced this issue Jan 2, 2024
Co-authored-by: Steffen Deusch <steffen.deusch@teaminternet.com>
@moomerman
Copy link

moomerman commented Jan 9, 2024

The fix in #2969 doesn't fix the bug I reported in this issue, I've created this single file reproduction of my issue:

image
^ Initial data

image
^^ clicking Filter removes A as expected

image
^^ after Reset, A is in the wrong place

Application.put_env(:sample, Example.Endpoint,
  http: [ip: {127, 0, 0, 1}, port: 5001],
  server: true,
  live_view: [signing_salt: "aaaaaaaa"],
  secret_key_base: String.duplicate("a", 64)
)

Mix.install([
  {:plug_cowboy, "~> 2.5"},
  {:jason, "~> 1.0"},
  {:phoenix, "~> 1.7.10", override: true},
  {:phoenix_live_view, github: "phoenixframework/phoenix_live_view", branch: "main"}
])

defmodule Example.ErrorView do
  def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end

defmodule Example.HomeLive do
  use Phoenix.LiveView, layout: {__MODULE__, :live}

  def mount(_params, _session, socket) do
    socket
    |> stream(:items, [
      %{id: "a", name: "A"},
      %{id: "b", name: "B"},
      %{id: "c", name: "C"},
      %{id: "d", name: "D"}
    ])
    |> then(&{:ok, &1})
  end

  def render("live.html", assigns) do
    ~H"""
    <script src="https://cdn.jsdelivr.net/npm/phoenix@1.7.10/priv/static/phoenix.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/phoenixframework/phoenix_live_view@main/priv/static/phoenix_live_view.js"></script>
    <script>
      let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
      liveSocket.connect()
    </script>
    <style>
      * { font-size: 1.1em; }
    </style>
    <%= @inner_content %>
    """
  end

  def render(assigns) do
    ~H"""
    <ul phx-update="stream" id="thelist">
      <li id={id} :for={{id, item} <- @streams.items}>
        <%= item.name %>
      </li>
    </ul>

    <button phx-click="filter">Filter</button>
    <button phx-click="reset">Reset</button>
    """
  end

  def handle_event("filter", _, socket) do
    {:noreply,
     stream(
       socket,
       :items,
       [
         %{id: "b", name: "B"},
         %{id: "c", name: "C"},
         %{id: "d", name: "D"}
       ],
       reset: true
     )}
  end

  def handle_event("reset", _, socket) do
    {:noreply,
     stream(
       socket,
       :items,
       [
         %{id: "a", name: "A"},
         %{id: "b", name: "B"},
         %{id: "c", name: "C"},
         %{id: "d", name: "D"}
       ],
       reset: true
     )}
  end
end

defmodule Example.Router do
  use Phoenix.Router
  import Phoenix.LiveView.Router

  pipeline :browser do
    plug(:accepts, ["html"])
  end

  scope "/", Example do
    pipe_through(:browser)

    live("/", HomeLive, :index)
  end
end

defmodule Example.Endpoint do
  use Phoenix.Endpoint, otp_app: :sample
  socket("/live", Phoenix.LiveView.Socket)
  plug(Example.Router)
end

{:ok, _} = Supervisor.start_link([Example.Endpoint], strategy: :one_for_one)
Process.sleep(:infinity)

@josevalim
Copy link
Member

@moomerman, moved to #2994.

chrismccord pushed a commit that referenced this issue Jan 17, 2024
Co-authored-by: Steffen Deusch <steffen.deusch@teaminternet.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants