How to Create a Basic PubSub Application
From ElixirBlocks
This page is in progress
In LiveView
def mount(_params, _session, socket) do
Testbeds.subscribe()
{:ok, assign(socket, testbeds: Testbeds.list_testbeds())}
end
def handle_info({TestBeds, [:testbed | _], _}, socket) do
{:noreply, assign(socket, testbeds: TestBeds.list_testbeds())}
end
App/test_beds.ex
@topic inspect(__MODULE__)
def subscribe do
Phoenix.PubSub.subscribe(App.PubSub, @topic)
end
defp broadcast_change({:ok, result}, event) do
Phoenix.PubSub.broadcast(App.PubSub, @topic, {__MODULE__, event, result})
{:ok, result}
end
# ....
def create_testbed(attrs \\ %{}) do
%Testbed{}
|> Testbed.changeset(attrs)
|> Repo.insert()
|> broadcast_change([:testbed, :created])
end
Example Without Database
defmodule AppWeb.PageLive do
use AppWeb, :live_view
def mount(_params, _session, socket) do
if connected?(socket) do
AppWeb.Endpoint.subscribe(topic)
end
{:ok, assign(socket, username: username, messages: [])}
end
def handle_info(%{event: "message", payload: message}, socket) do
{:noreply, assign(socket, messages: socket.assigns.messages ++ [message])}
end
def handle_event("send", %{"text" => text}, socket) do
AppWeb.Endpoint.broadcast(topic, "message", %{text: text, name: socket.assigns.username})
{:noreply, socket}
end
defp username do
"User #{:rand.uniform(100)}"
end
defp topic do
"chat"
end
def render(assigns)do
~H"""
<div>
<h1>ChatLive</h1>
<div class="messages" style="border: 1px solid #eee; height: 400px; overflow: scroll; margin-bottom: 8px;">
<%= for m <- @messages do %>
<p style="margin: 2px;"><b><%= m.name %></b>: <%= m.text %></p>
<% end %>
</div>
<form phx-submit="send">
<input type="text" name="text" />
<button type="submit">Send</button>
</form>
</div>
"""
end
end
# lib/app/counter.ex
defmodule Counter do
use Agent
def start_link(initial_value) do
Agent.start_link(fn -> initial_value end, name: __MODULE__)
end
def value do
Agent.get(__MODULE__, & &1)
end
def increment do
Agent.update(__MODULE__, &(&1 + 1))
end
end
# lib/app_web/live/page_live.ex
defmodule AppWeb.PageLive do
use AppWeb, :live_view
def mount(_params, _session, socket) do
Phoenix.PubSub.subscribe(App.PubSub, "the-topic")
# Get current value from the supervised Counter
data = Counter.value()
{:ok, assign(socket, data: data)}
end
def handle_event("increment", _params, socket) do
Counter.increment()
new_data = Counter.value()
Phoenix.PubSub.broadcast(App.PubSub, "the-topic", new_data)
{:noreply, assign(socket, data: new_data)}
end
def handle_info(new_data_from_broadcast, socket) do # usually set with pattern match like {:data,thedata}
IO.inspect new_data_from_broadcast
{:noreply, assign(socket, data: new_data_from_broadcast)}
end
def render(assigns) do
~H"""
<div>
<.button phx-click="increment">click me </.button>
<div>{@data}</div>
</div>
"""
end
end