LiveView auto-update on GenServer state change: possible?

I’m working on a small project which is (I think) perfect for LiveView and channels.

I want to have a sports scoreboard (e.g., which will require 2 parts: the actual scoreboard the spectators see, and the “control panel” for the scorekeeper who is keeping the score up to date.

These would essentially be 2 different browser windows on the same computer: the scorekeeper window would be on the laptop’s main screen, and the scoreboard would be displayed on a secondary screen via HDMI output. In other words, everything would be running locally: LiveView and channels would essentially be used to keep the 2 browser windows in sync.

The scorekeeper will have to increment each team’s points, etc. which will be a great fit for LiveView.

In addition, every time the game information changes (basically every point), the scoreboard will have to update to display the updated information.

Currently I’m keeping track of the game state in a GenServer, and the various web pages fetch the game state when necessary.

For the scoreboard, this means I’m already rendering an eex template with the game state. My initial idea what to then use channels to update the scoreboard, but that would mean I also have to write all the js selectors etc. to update the various scoreboard elements as they change.

What I think would make more sense is for the scoreboard to be a LiveView that somehow updates on every state change that happens in the game state GenServer. Is this at all possible?

The LiveView docs cover a topic that is similar to what I’d like to achieve ( but relies on periodically sending messages to self(). I could send messages to reassign the state to the socket every 500ms, but I feel there’s probably a better way…

1 Like

There’s an example app that uses a Phoenix.PubSub to listen for changes in the mount callback and update assign in handle_info

def mount(%{path_params: %{"id" => id}}, socket) do
    if connected?(socket), do: Demo.Accounts.subscribe(id)
    {:ok, fetch(assign(socket, id: id))}

Shame on me: it didn’t even occur to me to check the examples for a similar use case… Thanks for pointing me in the right direction, this looks like exactly what I’m after!

1 Like