How to replace LiveView stream with new items? (reset or re-assigning)

I expected that the existing stream to be replaced with new items when stream is assigned again, but it isn’t.
It crashes with ** (ArgumentError) existing hook :messages(stream name) already attached on :after_render.

  @impl true
  def update(assigns, socket) do
    ...

    socket =
      socket
      |> assign(assigns)
      |> assign_messages(new_channel_name)

    {:ok, socket}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div>
      <.h2># <%= @channel_name %></.h2>
      <p>Your ID: <%= @session_id %></p>
      <div id="messages" class="h-96 overflow-y-auto" phx-update="stream" phx-hook="ChatMessages">
        <div :for={{message_id, message} <- @streams.messages} id={message_id} class="mt-4">
          <p>User id: <%= message.user_id %></p>
          <p><%= message.created_at %></p>
          <p><%= message.body %></p>
        </div>
      </div>
      ...
    </div>
    """
  end

  defp assign_messages(socket, channel_name) do
    {:ok, messages} = Chat.list_messages(channel_name)

    socket
    |> stream(:messages, messages)
    ...
  end

You can test it on the page below, by changing channel.

Is it possible to replace stream with new items? (re-assigning)

page: Home · Json Media
code: json_corp/channel.ex at chat · nallwhy/json_corp · GitHub

1 Like

At the moment, you can stream_insert to update or add or stream_delete to delete individual elements e.g. message within @streams.messages within an existing stream. Emptying/clearing out an existing stream at the @streams.messages level isn’t currently supported, but it is on the roadmap.

2 Likes

Thank you!