Skip to content

Instantly share code, notes, and snippets.

@westmark
Last active October 21, 2025 08:53
Show Gist options
  • Select an option

  • Save westmark/7021bc0ede74838616ac937dd07b59a7 to your computer and use it in GitHub Desktop.

Select an option

Save westmark/7021bc0ede74838616ac937dd07b59a7 to your computer and use it in GitHub Desktop.
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.8.1"},
# please test your issue using the latest version of LV from GitHub!
{:phoenix_live_view,
github: "phoenixframework/phoenix_live_view", branch: "main", override: true}
])
# if you're trying to test a specific LV commit, it may be necessary to manually build
# the JS assets. To do this, uncomment the following lines:
# this needs mix and npm available in your path!
#
# path = Phoenix.LiveView.__info__(:compile)[:source] |> Path.dirname() |> Path.join("../")
# System.cmd("mix", ["deps.get"], cd: path, into: IO.binstream())
# System.cmd("npm", ["install"], cd: Path.join(path, "./assets"), into: IO.binstream())
# System.cmd("mix", ["assets.build"], cd: path, into: IO.binstream())
defmodule Example.ErrorView do
def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end
defmodule Example.ReproLiveComponentWithAsyncResult do
use Phoenix.LiveComponent
def mount(socket) do
{:ok, socket}
end
def render(assigns) do
~H"""
<div>
<.async_result :let={data} assign={@data}>
<p :for={item <- data} :key={item.id}>{item.value}</p>
</.async_result>
</div>
"""
end
def handle_event(_, _, socket) do
{:noreply, socket}
end
end
defmodule Example.ReproLiveComponent do
use Phoenix.LiveComponent
def mount(socket) do
{:ok, socket}
end
def render(assigns) do
~H"""
<div>
<p :for={item <- @data} :key={item.id}>{item.value}</p>
</div>
"""
end
def handle_event(_, _, socket) do
{:noreply, socket}
end
end
defmodule Example.HomeLive do
use Phoenix.LiveView, layout: {__MODULE__, :live}
alias Phoenix.LiveView.AsyncResult
def mount(_params, _session, socket) do
{:ok, socket |> assign(:data, AsyncResult.ok([]))}
end
def render("live.html", assigns) do
~H"""
<script src="/assets/phoenix/phoenix.js">
</script>
<script src="/assets/phoenix_live_view/phoenix_live_view.js">
</script>
<%!-- uncomment to use enable tailwind --%>
<%!-- <script src="https://cdn.tailwindcss.com"></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"""
<div class="p-4">
<p class="my-4">
Click Load Data. 3 items should be displayed. Then click Remove First entry. The expected result is 2 items displayed.
</p>
<div>
<.async_result :let={data} assign={@data}>
<.live_component module={Example.ReproLiveComponent} id="repro" data={data} />
</.async_result>
<!-- Uncomment the below to get a different issue
<div style="margin: 10px; height: 1px; background-color: black;"></div>
<.live_component
module={Example.ReproLiveComponentWithAsyncResult}
id="repro_async"
data={@data}
/>
-->
</div>
<div>
<button phx-click="load">Load data</button>
<button phx-click="remove">Remove first entry</button>
</div>
</div>
"""
end
def handle_event("load", _, socket) do
socket =
assign_async(socket, :data, fn ->
Process.sleep(100)
{:ok,
%{data: [%{id: 1, value: "First"}, %{id: 2, value: "Second"}, %{id: 3, value: "Third"}]}}
end)
{:noreply, socket}
end
def handle_event("remove", _, socket) do
socket =
assign_async(socket, :data, fn ->
Process.sleep(100)
{:ok, %{data: [%{id: 2, value: "Second"}, %{id: 3, value: "Third"}]}}
end)
{:noreply, socket}
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 Plug.Static, from: {:phoenix, "priv/static"}, at: "/assets/phoenix"
plug Plug.Static, from: {:phoenix_live_view, "priv/static"}, at: "/assets/phoenix_live_view"
plug(Example.Router)
end
{:ok, _} = Supervisor.start_link([Example.Endpoint], strategy: :one_for_one)
Process.sleep(:infinity)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment