/
assign_live.ex
96 lines (76 loc) · 2.51 KB
/
assign_live.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
defmodule StreamTestWeb.AssignLive do
use StreamTestWeb, :live_view
## Models
defmodule Thing do
defstruct [:id, :text]
def new(text) do
%__MODULE__{id: Ecto.UUID.generate(), text: text}
end
end
defmodule ThingCollection do
defstruct [:id, :things]
def new(things) when is_list(things) do
%__MODULE__{id: Ecto.UUID.generate(), things: things}
end
end
## Mount + Render
def mount(_params, _session, socket) do
{:ok, assign(socket, :thing_collections, [])}
end
def render(assigns) do
~H"""
<div id="thing_collections" class="flex flex-row" phx-update="stream">
<div :for={collection <- @thing_collections} id={"collection-#{collection.id}"}>
<.display_thing_collection
collection={collection}
stream={@streams[collection_id_to_stream_name(collection.id)]}
/>
</div>
</div>
<.button phx-click="new-thing-collection">New thing collection</.button>
"""
end
## Callbacks
def handle_event("new-thing-collection", _params, socket) do
new_collection = ThingCollection.new([])
{:noreply,
socket
|> assign(:thing_collections, [new_collection | socket.assigns.thing_collections])
|> stream(collection_id_to_stream_name(new_collection.id), new_collection.things)}
end
def handle_event("new-thing", %{"collection" => collection_id}, socket) do
{:noreply,
stream_insert(
socket,
collection_id_to_stream_name(collection_id),
Thing.new("hello world")
)}
end
def handle_event("delete-thing", %{"collection" => collection_id, "thing" => thing_id}, socket) do
{:noreply, stream_delete(socket, collection_id_to_stream_name(collection_id), %Thing{id: thing_id})}
end
## Helpers
# Functions
defp collection_id_to_stream_name(collection_id) do
"thing_collection-#{collection_id}"
end
# Components
attr :collection, :any, doc: "The ThingCollection to display"
attr :stream, :any, doc: "The stream of Things for this collection"
defp display_thing_collection(assigns) do
~H"""
<div id={"things-for-collection-#{@collection.id}"} phx-update="stream" class="border">
<div
:for={{dom_id, thing} <- @stream}
id={dom_id}
phx-click="delete-thing"
phx-value-collection={@collection.id}
phx-value-thing={thing.id}
>
<span><%= thing.text %></span>
</div>
</div>
<.button phx-click="new-thing" phx-value-collection={@collection.id}>New thing</.button>
"""
end
end