Filament.Observable.GenServer (filament v0.2.1)

Copy Markdown

Macro that makes a GenServer observable by Filament components.

use Filament.Observable.GenServer injects:

  • handle_call({:filament_subscribe, subscriber}, from, state) — subscriber registration; calls handle_subscribe/2 (overridable)
  • handle_cast({:filament_remove_projection, owner_pid, proj_key}, state) — projection removal; auto-unsubscribes when the last projection is removed
  • handle_info({:DOWN, ref, :process, pid, reason}, state) — automatic subscriber cleanup when a LiveView process terminates
  • notify_observers/1 — call this from your handlers whenever state changes to push raw state to all subscribed components

Subscribers are keyed by owner_pid. All fibers within the same LiveView that subscribe to the same server share one subscriber entry. Each fiber registers a named projection key; notify_observers/1 sends one {:filament_observable_updates, [{fiber_id, slot_index, raw_state}]} message per subscriber whenever the raw state changes (change-or-bust at subscriber level). Projection fns run client-side on each re-render, so closures over local component state (filters, selections, etc.) always see the current value.

Example

defmodule MyApp.Counter do
  use Filament.Observable.GenServer

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, 0, name: Keyword.get(opts, :name, __MODULE__))
  end

  @impl GenServer
  def init(initial), do: {:ok, initial}

  @impl Filament.Observable
  def handle_subscribe(_subscriber, state) do
    {:ok, state, state}
  end

  @impl GenServer
  def handle_call(:increment, _from, count) do
    new_count = count + 1
    notify_observers(new_count)
    {:reply, new_count, new_count}
  end
end