sercrod

*websocket

Summary

*websocket opens and manages WebSocket connections for a Sercrod host and its descendants.

Basic examples

Host-level connection with state flags:

<serc-rod id="chat"
         data='{"wsUrl": "wss://example.com/chat"}'
         *websocket="wsUrl"
         *into="wsData">
  <section>
    <p>
      Status:
      <strong *print="$ws_ready ? 'connected' : 'disconnected'"></strong>
    </p>

    <p *if="$ws_error">
      Last error: <span *print="$ws_error"></span>
    </p>

    <pre *if="wsData"
         *textContent="JSON.stringify(wsData, null, 2)"></pre>
  </section>
</serc-rod>

Element-level connection and sending:

<serc-rod id="notify"
         data='{
           "notifyUrl": "wss://example.com/notify",
           "payload": { "type": "ping" }
         }'>

  <!-- Connect on button click -->
  <button *websocket="notifyUrl"
          *into="lastNotify">
    Connect notification channel
  </button>

  <!-- Send via the same URL (selected by *ws-to on *ws-send) -->
  <button *ws-send="payload"
          *ws-to="%notifyUrl%">
    Send ping
  </button>

  <pre *if="lastNotify"
       *textContent="JSON.stringify(lastNotify, null, 2)"></pre>
</serc-rod>

Host vs element usage

*websocket can be attached to:

  1. The Sercrod host (<serc-rod>) as a host attribute:

    • *websocket="spec"
    • Optional: *into="propName"

    Example:

    • <serc-rod *websocket="wsUrl" *into="wsData">…</serc-rod>

    Behavior:

    • The host resolves spec into a URL (and optional into) from the host scope.
    • It attempts a connection once, asynchronously, after the initial render.
    • The connection is tracked per URL and controlled by the host’s websocket controller.
  2. Any element inside a Sercrod host:

    • *websocket="spec" on a child element (for example button, a, div) creates or reuses a connection for that URL.

    Behavior:

    • The directive is rendered as a “special element”:
      • Sercrod clones the element (without children), wires the WebSocket logic, and appends the clone.
      • Children of the original element are rendered normally into the clone.
    • The connection is still owned by the host (the WebSocket state lives on the host’s data object), but events are dispatched from the element.

Clickable vs non-clickable elements:

Spec expression and URL resolution

The spec expression on *websocket can be:

Resolution steps (for both host and element):

  1. Evaluate the spec as a Sercrod expression in mode: "attr".

    • Example: *websocket="wsUrl" or *websocket="config.ws".
  2. If the expression result is null or is exactly the same as the raw string, treat it as a template string and run Sercrod’s text expansion:

    • ${expr} is evaluated like other Sercrod template expansions.
    • %name% placeholders can also be used and are expanded from the current scope.
  3. Interpret the final value:

    • If it is an object, the runtime accepts:
      • url: the WebSocket URL (string, required).
      • protocols: reserved for future use (currently ignored).
      • into: optional property name that indicates where to store incoming messages.
    • Otherwise, the value is treated as the URL string.

Examples:

<!-- Simple string or data binding -->
<serc-rod *websocket="'wss://example.com/ws'"></serc-rod>
<serc-rod *websocket="wsUrl"></serc-rod>

<!-- Template-style expansion -->
<serc-rod *websocket="'wss://example.com/ws/%roomId%'"></serc-rod>

<!-- Object-style spec -->
<serc-rod *websocket="{ url: wsUrl, into: 'wsData' }"></serc-rod>

Placeholder guard:

Data integration and state fields

*websocket ensures that the host’s data object has the following fields:

Connection metadata:

Message storage:

Notes:

Using *into with *websocket

You can choose where incoming messages are stored with *into or by specifying into in the spec object:

Examples:

<!-- Host-level with *into -->
<serc-rod *websocket="wsUrl" *into="wsData">
  <pre *textContent="JSON.stringify(wsData, null, 2)"></pre>
</serc-rod>

<!-- Element-level with *into -->
<button *websocket="wsUrl" *into="wsMessage">
  Connect and keep last message in wsMessage
</button>

<!-- Object spec provides into -->
<serc-rod *websocket="{ url: wsUrl, into: 'wsData' }"></serc-rod>

Events and lifecycle hooks

*websocket dispatches custom DOM events that you can listen to on the host or on the element that owns the directive.

Lifecycle events:

Dispatch target:

WebSocket controller (el.websocket)

Each Sercrod host exposes a lightweight controller object on the host element:

Properties and methods (simplified view):

This controller is useful for advanced orchestration and custom reconnection strategies, but most templates can rely on *websocket plus *ws-send and *ws-to without calling it directly.

Interaction with *ws-send and *ws-to

*websocket establishes and tracks connections; *ws-send and *ws-to send messages over them.

Connection map:

Sending:

*ws-to / n-ws-to:

Restrictions:

Evaluation timing and reconnection

Host-level auto connect:

Element-level connect:

Placeholder behavior:

Best practices

Notes