PhoenixDatastar.Socket (PhoenixDatastar v0.2.0)

Copy Markdown View Source

Socket struct for PhoenixDatastar, similar to Phoenix.LiveView.Socket. Holds the view module, session id, assigns, signals, private data, and queued events.

Assigns vs Signals

  • Assigns are server-side state, never sent to the client. Use assign/2,3 and update/3 to work with assigns. They are available in templates as @key.

  • Signals are Datastar reactive state sent to the client via SSE. Use put_signal/2,3 and update_signal/3 to work with signals. They must be JSON-serializable. The client accesses them via Datastar expressions like $count. Signals are not available as @key in templates — Datastar handles their rendering client-side.

Summary

Functions

Merges assigns into the socket from a map or keyword list.

Assigns a single key-value pair to the socket's server-side assigns.

Queues a console.log to be executed on the client via SSE.

Queues a JavaScript script to be executed on the client via SSE.

Creates a new socket with standard assigns.

Queues an HTML patch to be sent via SSE.

Merges signals into the socket from a map or keyword list.

Puts a single Datastar signal on the socket.

Queues a redirect to be executed on the client via SSE.

Updates an assign using a function.

Updates a signal using a function.

Types

event()

@type event() ::
  {:patch, String.t(), String.t()}
  | {:patch, String.t(), String.t(), keyword()}
  | {:script, String.t(), keyword()}

t()

@type t() :: %PhoenixDatastar.Socket{
  assigns: map(),
  events: [event()],
  id: String.t() | nil,
  private: map(),
  signals: map(),
  view: module()
}

Functions

assign(socket, new_assigns)

@spec assign(t(), map() | keyword()) :: t()

Merges assigns into the socket from a map or keyword list.

Examples

assign(socket, %{user: user, settings: settings})
assign(socket, user: user, settings: settings)

assign(socket, key, value)

@spec assign(t(), atom(), any()) :: t()

Assigns a single key-value pair to the socket's server-side assigns.

Assigns are never sent to the client. Use put_signal/3 for client-side Datastar signals.

Examples

assign(socket, :user, %User{name: "Alice"})

console_log(socket, message, opts \\ [])

@spec console_log(t(), term(), keyword()) :: t()

Queues a console.log to be executed on the client via SSE.

Options

  • :level - Console method: :log, :warn, :error, :info, :debug (default: :log)
  • Plus all options from execute_script/3

Examples

socket
|> console_log("Debug message")

socket
|> console_log("Warning!", level: :warn)

socket
|> console_log(%{user: "alice", action: "login"}, level: :info)

execute_script(socket, script, opts \\ [])

@spec execute_script(t(), String.t(), keyword()) :: t()

Queues a JavaScript script to be executed on the client via SSE.

Options

  • :auto_remove - Remove script tag after execution (default: true)
  • :attributes - Map of additional script tag attributes

Examples

socket
|> execute_script("alert('Hello!')")

socket
|> execute_script("console.log('debug')", auto_remove: false)

# ES module script
socket
|> execute_script("import {...} from 'module'", attributes: %{type: "module"})

new(session_id, view, base_path, opts \\ [])

@spec new(String.t(), module(), String.t(), keyword()) :: t()

Creates a new socket with standard assigns.

Options

  • :live - Whether this is a live (stateful) view. Defaults to true. When false, stream_path is set to nil.
  • :flash - Flash map. Defaults to %{}.

Examples

Socket.new(session_id, MyApp.CounterStar, "/counter")
Socket.new(session_id, MyApp.PageStar, "/about", live: false)

patch_elements(socket, selector, render_fn)

@spec patch_elements(
  t(),
  String.t(),
  (map() -> Phoenix.HTML.Safe.t()) | Phoenix.HTML.Safe.t()
) :: t()

Queues an HTML patch to be sent via SSE.

The selector is a CSS selector targeting the element to patch. The second argument can be either:

  • A render function that takes assigns and returns HTML
  • Raw HTML content (must implement Phoenix.HTML.Safe)

The render function receives socket.assigns (server-side state only, not signals).

Examples

With a render function (recommended for pipelines):

socket
|> assign(:items, updated_items)
|> patch_elements("#items", &render_items/1)
|> then(&{:noreply, &1})

defp render_items(assigns) do
  ~H|<ul id="items"><li :for={item <- @items}>{item}</li></ul>|
end

With raw HTML:

socket
|> patch_elements("#count", ~H"<span id="count">42</span>")

put_signal(socket, new_signals)

@spec put_signal(t(), map() | keyword()) :: t()

Merges signals into the socket from a map or keyword list.

Examples

put_signal(socket, %{count: 0, name: "test"})
put_signal(socket, count: 0, name: "test")

put_signal(socket, key, value)

@spec put_signal(t(), atom(), any()) :: t()

Puts a single Datastar signal on the socket.

Signals are sent to the client and must be JSON-serializable. They are accessed client-side via Datastar expressions (e.g., $count).

Examples

put_signal(socket, :count, 0)

redirect(socket, url, opts \\ [])

@spec redirect(t(), String.t(), keyword()) :: t()

Queues a redirect to be executed on the client via SSE.

Uses setTimeout for proper browser history handling, especially in Firefox.

Options

Same as execute_script/3.

Examples

socket
|> redirect("/dashboard")

socket
|> redirect("https://example.com")

update(socket, key, fun)

@spec update(t(), atom(), (any() -> any())) :: t()

Updates an assign using a function.

Examples

update(socket, :user, &User.increment_visits/1)

update_signal(socket, key, fun)

@spec update_signal(t(), atom(), (any() -> any())) :: t()

Updates a signal using a function.

Examples

update_signal(socket, :count, &(&1 + 1))