sercrod

*save

Summary

*save.file exports the host data (or its staged view) as a JSON file in the browser. *save.session stores the same JSON payload in browser sessionStorage. *save.store stores the same JSON payload in persistent browser storage backed by IndexedDB. It is typically used on a button inside a <serc-rod> host. When clicked, Sercrod collects the host’s current data and builds a JSON string. File saves start a download; session saves write that string under the storage key given by *save.session; store saves write it under the key given by *save.store.

By default, *save exports the entire host data. Use *keys to export only selected top-level properties. *save remains as the legacy-compatible file form, equivalent to *save.file when no storage suffix is used.

Basic example

Save the entire host data:

<serc-rod id="profile" data='{"name":"Alice","age":30}'>
  <button *save.file>Download profile JSON</button>
</serc-rod>

Behavior:

Save selected keys to an explicit filename:

<button type="button" *save.file="'profile-backup.json'" *keys="profile settings">
  Save profile
</button>

In this form:

Save selected keys into the current browser session:

<button type="button" *save.session="'profile-draft'" *keys="profile settings">
  Save session draft
</button>

In this form:

Save selected keys into persistent browser storage:

<button type="button" *save.store="'profile-draft'" *keys="profile settings">
  Save persistent draft
</button>

In this form:

Behavior

Aliases and compatibility:

Data source and property selection

Data source:

Key selection:

Example (selective save):

<serc-rod id="settings" data='{
  "user": { "name": "Alice", "age": 30 },
  "theme": { "mode": "dark" },
  "debug": true
}'>
  <!-- Only save "user" and "theme" from the host data -->
  <button *save.file="'user-theme.json'" *keys="user theme">Download user+theme</button>
</serc-rod>

In this example:

Old spelling:

<button *save="user theme">Download user+theme</button>

This remains supported for compatibility. Treat the value as old *keys syntax, not as a filename.

Evaluation timing

Render-time:

Click-time:

Because the JSON is built at click time, *save always reflects the current state of _stage or _data at the moment of the click.

Execution model

Internally, *save behaves as follows (conceptually):

  1. During render, Sercrod finds an element work with a save directive.

  2. Sercrod clones work into el.

  3. Sercrod attaches:

    • el.addEventListener("click", () => { /* build JSON and save to the selected destination */ }).
  4. Sercrod appends el to the parent node and returns, without processing el’s children for further Sercrod directives.

On click, the handler:

  1. Resolves the action attribute and *keys.

  2. Selects src:

    • src = host._stage ?? host._data.
  3. Builds data:

    • If there is a *keys list, data is a new object populated only with properties present in src.
    • Otherwise, data is src itself.
  4. Serializes data with a pretty-printed JSON.stringify(data, null, 2).

  5. If the action is *save.store, writes { key, json, updatedAt } into the configured IndexedDB object store and returns.

  6. If the action is *save.session, writes the JSON string with sessionStorage.setItem(storageKey, json) and returns.

  7. Otherwise, creates a Blob of type application/json.

  8. Creates an ObjectURL and a temporary <a> element with:

    • href = url.
    • download = "Sercrod-YYYYMMDD-HHMMSS.json" (in the local time of the browser).
  9. Programmatically clicks the anchor to prompt download.

  10. Cleans up (removes the anchor from the DOM and revokes the ObjectURL).

  11. Dispatches CustomEvent("sercrod-saved", { detail: { ... } }) from the host.

Use on nested elements and scope

In other words:

Events

After a successful save, Sercrod dispatches a bubbling, composed CustomEvent from the host:

Example hook:

document.addEventListener("sercrod-saved", (evt) => {
  const { host, fileName, storage, storageKey, props, json } = evt.detail;
  console.log("Saved from host:", host.id);
  console.log("File name:", fileName);
  console.log("Storage:", storage, storageKey);
  console.log("Props:", props);
  console.log("JSON preview:", json.slice(0, 200));
});

You can use this event to:

Best practices

Advanced - Using save forms with *stage, *apply, *restore, load forms, and *post

*save is part of a broader data management workflow:

The core rule is:

Notes