sreyansjain

sreyansjain

Strange behavior of Liveview streams when using reset: true

I am trying to use the main branch of phoenix liveview to test the new reset feature on streams
In my mix.exs I have

{:phoenix_live_view,
       github: "phoenixframework/phoenix_live_view", branch: "main", override: true}

I have created a simple liveview example for a phonebook.
I have a list of names and an index at the top. Clicking on the index should load the contacts that start with the Index letter.
Whenever the index letter is clicked, i load all the relevant contacts, put them in the stream and set the reset flag to true.
This is working fine.

The Problem

Clicking on each contact opens up a modal with the contact details.
This works fine for the first time. Click on the modal, the modal appears.

But whenever the stream gets reset (after clicking a index letter), clicking on the contact brings up the modal, but the stream gets cleared and all contacts disappear.
I am not able to figure out why this is happening.
I tried to replace the stream, with normal assigns and everything works like it should (the modal appears and the contacts do not get cleared).

Can some one please advise as to why is this happening?

Full code is below

defmodule StreamsTestWeb.UserLive.Index do
  use StreamsTestWeb, :live_view

  @impl true
  def render(assigns) do
    ~H"""
    <div class="h-20 flex items-center space-x-12 border-b border-zinc-200 px-4 lg:px-8">
      <div class="text-lg font-bold">Users</div>
    </div>
    <div class="tabs flex items-center gap-2 text-xs font-medium px-r lg:px-8 mt-8">
      <.tab :for={tab <- @tabs} tab={tab} selected_tab={@selected_tab} />
    </div>
    <div :if={@term != ""} class="flex items-center gap-4 text-sm px-4 lg:px-8 mt-6">
      <div class="text-zinc-500">Searching <em class="font-bold text-zinc-700"><%= @term %></em></div>
      <button
        type="button"
        class="flex items-center gap-2 text-xs text-zinc-400 hover:text-zinc-600"
        phx-click="clear_search"
      >
        <.icon name="hero-x-circle" class="w-5 h-5" />
      </button>
    </div>
    <div class="px-4 lg:px-8">
      <.table
        id="users"
        rows={@streams.users}
        row_click={fn {_id, u} -> JS.push("show_user", value: %{id: u.id}) end}
      >
        <:col :let={{_id, s}} label="Name">
          <%= s.name %>
        </:col>
      </.table>
    </div>
    <div id="modal_box">
      <.modal :if={@user} id="detail-modal" show on_cancel={JS.push("hide_user")}>
        <.header><%= @user.name %></.header>
      </.modal>
    </div>
    """
  end

  @impl true
  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:tabs, get_tabs())
      |> assign(:selected_tab, "All")
      |> assign(:term, "")
      |> assign(:user, nil)
      |> stream(:users, get_users)

    {:ok, stream(socket, :users, [])}
  end

  attr(:tab, :string, required: true)
  attr(:selected_tab, :string, required: true)

  def tab(assigns) do
    ~H"""
    <div
      class={[
        "w-6 h-6 inline-flex items-center justify-center rounded cursor-pointer",
        @tab == @selected_tab && "text-green-700 bg-green-100",
        @tab != @selected_tab && "text-zinc-500 bg-transparent hover:text-zinc-700 hover:bg-zinc-100"
      ]}
      phx-click="load_contacts"
      phx-value-index={@tab}
    >
      <%= @tab %>
    </div>
    """
  end

  @impl true
  def handle_event("load_contacts", %{"index" => index}, socket) do
    users = get_users() |> Enum.filter(fn s -> String.starts_with?(s.name, index) end)

    socket =
      socket
      |> assign(:selected_tab, index)
      |> assign(:term, "")
      |> assign(:user, nil)
      |> stream(:users, users, reset: true)

    {:noreply, socket}
  end

  def handle_event("show_user", %{"id" => id}, socket) do
    socket =
      assign(
        socket,
        :user,
        Enum.find(get_users, fn u -> u.id == id end)
      )

    {:noreply, socket}
  end

  def handle_event("hide_user", _params, socket) do
    socket =
      assign(
        socket,
        :user,
        nil
      )

    {:noreply, socket}
  end

  defp get_tabs() do
    [
      "A",
      "B",
      "C",
      "D",
      "E",
      "F",
      "G",
      "H",
      "I",
      "J",
      "K",
      "L",
      "M",
      "N",
      "O",
      "P",
      "Q",
      "R",
      "S",
      "T",
      "U",
      "V",
      "W",
      "X",
      "Y",
      "Z"
    ]
  end

  def get_users() do
    [
      %{id: 1, name: "A Name"},
      %{id: 2, name: "B Name"},
      %{id: 3, name: "C Name"},
      %{id: 4, name: "D Name"},
      %{id: 5, name: "E Name"},
      %{id: 6, name: "F Name"},
      %{id: 7, name: "G Name"},
      %{id: 8, name: "H Name"},
      %{id: 9, name: "I Name"},
      %{id: 10, name: "J Name"}
    ]
  end
end

Marked As Solved

chrismccord

chrismccord

Creator of Phoenix

This is fixed on main. Thank you!

Also Liked

chrismccord

chrismccord

Creator of Phoenix

Are you positive the table’s tbody has phx-update="stream" ?

Where Next?

Popular in Questions Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: &lt;h1&gt;Create Post&lt;/h1&gt; &lt;%= ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41989 114
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement