Skip to content

Commit 2ac64d1

Browse files
committed
stream_insert update_only aka stream_update
Fixes #2690. Relates to: https://elixirforum.com/t/add-stream-update-to-liveview-streams/68107 Work in progress, no tests yet.
1 parent 51db662 commit 2ac64d1

6 files changed

Lines changed: 21 additions & 11 deletions

File tree

assets/js/phoenix_live_view/dom_patch.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ export default class DOMPatch {
144144
}
145145
},
146146
onBeforeNodeAdded: (el) => {
147+
// don't add update_only nodes if they did not already exist
148+
if(this.getStreamInsert(el)?.updateOnly && !this.streamComponentRestore[el.id]){
149+
return false
150+
}
151+
147152
DOM.maintainPrivateHooks(el, el, phxViewportTop, phxViewportBottom)
148153
this.trackBefore("added", el)
149154

@@ -296,8 +301,8 @@ export default class DOMPatch {
296301

297302
liveSocket.time("morphdom", () => {
298303
this.streams.forEach(([ref, inserts, deleteIds, reset]) => {
299-
inserts.forEach(([key, streamAt, limit]) => {
300-
this.streamInserts[key] = {ref, streamAt, limit, reset}
304+
inserts.forEach(([key, streamAt, limit, updateOnly]) => {
305+
this.streamInserts[key] = {ref, streamAt, limit, reset, updateOnly}
301306
})
302307
if(reset !== undefined){
303308
DOM.all(container, `[${PHX_STREAM_REF}="${ref}"]`, child => {

lib/phoenix_live_view.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,9 @@ defmodule Phoenix.LiveView do
18341834
here as well in order to be enforced. See `stream/4` for more information on
18351835
limiting streams.
18361836
1837+
* `:update_only` - A boolean to only update the item in the stream. If the item does not
1838+
exist on the client, it will not be inserted. Defaults to `false`.
1839+
18371840
## Examples
18381841
18391842
Imagine you define a stream on mount with a single item:
@@ -1878,8 +1881,9 @@ defmodule Phoenix.LiveView do
18781881
def stream_insert(%Socket{} = socket, name, item, opts \\ []) do
18791882
at = Keyword.get(opts, :at, -1)
18801883
limit = Keyword.get(opts, :limit)
1884+
update_only = Keyword.get(opts, :update_only, false)
18811885

1882-
update_stream(socket, name, &LiveStream.insert_item(&1, item, at, limit))
1886+
update_stream(socket, name, &LiveStream.insert_item(&1, item, at, limit, update_only))
18831887
end
18841888

18851889
@doc """

lib/phoenix_live_view/engine.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ defmodule Phoenix.LiveView.Comprehension do
8484

8585
@doc false
8686
def __annotate__(comprehension, %Phoenix.LiveView.LiveStream{} = stream) do
87-
inserts = for {id, at, _item, limit} <- stream.inserts, do: [id, at, limit]
87+
inserts = for {id, at, _item, limit, update_only} <- stream.inserts, do: [id, at, limit, update_only]
8888
data = [stream.ref, inserts, stream.deletes]
8989

9090
if stream.reset? do

lib/phoenix_live_view/live_stream.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule Phoenix.LiveView.LiveStream do
2020
"stream :dom_id must return a function which accepts each item, got: #{inspect(dom_id)}"
2121
end
2222

23-
items_list = for item <- items, do: {dom_id.(item), -1, item, opts[:limit]}
23+
items_list = for item <- items, do: {dom_id.(item), -1, item, opts[:limit], opts[:update_only]}
2424

2525
%LiveStream{
2626
ref: ref,
@@ -58,10 +58,10 @@ defmodule Phoenix.LiveView.LiveStream do
5858
%{stream | deletes: [dom_id | stream.deletes]}
5959
end
6060

61-
def insert_item(%LiveStream{} = stream, item, at, limit) do
61+
def insert_item(%LiveStream{} = stream, item, at, limit, update_only) do
6262
item_id = stream.dom_id.(item)
6363

64-
%{stream | inserts: stream.inserts ++ [{item_id, at, item, limit}]}
64+
%{stream | inserts: stream.inserts ++ [{item_id, at, item, limit, update_only}]}
6565
end
6666

6767
defimpl Enumerable, for: LiveStream do
@@ -86,7 +86,7 @@ defmodule Phoenix.LiveView.LiveStream do
8686
defp do_reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &do_reduce(list, &1, fun)}
8787
defp do_reduce([], {:cont, acc}, _fun), do: {:done, acc}
8888

89-
defp do_reduce([{dom_id, _at, item, _limit} | tail], {:cont, acc}, fun) do
89+
defp do_reduce([{dom_id, _at, item, _limit, _update_only} | tail], {:cont, acc}, fun) do
9090
do_reduce(tail, fun.({dom_id, item}, acc), fun)
9191
end
9292

lib/phoenix_live_view/test/dom.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,8 @@ defmodule Phoenix.LiveViewTest.DOM do
464464

465465
streamInserts =
466466
Enum.reduce(streams, %{}, fn %{ref: ref, inserts: inserts}, acc ->
467-
Enum.reduce(inserts, acc, fn [id, stream_at, limit], acc ->
467+
# TODO: support update_only in LiveViewTest
468+
Enum.reduce(inserts, acc, fn [id, stream_at, limit, _update_only], acc ->
468469
Map.put(acc, id, %{ref: ref, stream_at: stream_at, limit: limit})
469470
end)
470471
end)

test/phoenix_live_view/live_stream_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ defmodule Phoenix.LiveView.LiveStreamTest do
1313

1414
test "default dom_id" do
1515
stream = LiveStream.new(:users, 0, [%{id: 1}, %{id: 2}], [])
16-
assert stream.inserts == [{"users-1", -1, %{id: 1}, nil}, {"users-2", -1, %{id: 2}, nil}]
16+
assert stream.inserts == [{"users-1", -1, %{id: 1}, nil, nil}, {"users-2", -1, %{id: 2}, nil, nil}]
1717
end
1818

1919
test "custom dom_id" do
2020
stream = LiveStream.new(:users, 0, [%{name: "u1"}, %{name: "u2"}], dom_id: &"u-#{&1.name}")
21-
assert stream.inserts == [{"u-u1", -1, %{name: "u1"}, nil}, {"u-u2", -1, %{name: "u2"}, nil}]
21+
assert stream.inserts == [{"u-u1", -1, %{name: "u1"}, nil, nil}, {"u-u2", -1, %{name: "u2"}, nil, nil}]
2222
end
2323

2424
test "default dom_id without struct or map with :id" do

0 commit comments

Comments
 (0)