sercrod

*for

Summary

*for repeats the host element for each entry in a list, object, or other iterable. The host element itself is duplicated as many times as needed, and each clone is rendered with its own iteration scope. The directive understands JavaScript-like in and of loop syntax and has an alias n-for.

There is also a special host-level form when *for is placed directly on a Sercrod host (<serc-rod>). In that case the host is not repeated; instead, the inner template is rendered multiple times inside the same host with different scopes.

Structural restriction:

Basic example

Classic list items:

<serc-rod id="app" data='{"items":["Apple","Banana","Cherry"]}'>
  <ul>
    <li *for="item of items">
      <span *print="item"></span>
    </li>
  </ul>
</serc-rod>

Behavior:

Behavior

Element-level *for:

Host-level *for on <serc-rod>:

Expression syntax

The expression to the right of *for uses a restricted, JS-like loop syntax:

key and value must be simple identifiers (no destructuring patterns).

Supported patterns for element-level *for:

Host-level *for on <serc-rod> uses the same syntax but normalizes it slightly differently (see the dedicated section below).

Value semantics (element-level *for)

Element-level *for distinguishes of and in like JavaScript:

Deprecation note:

Evaluation timing

Element-level *for participates in Sercrod’s structural evaluation order inside renderNode:

Important consequences:

Host-level *for is evaluated during the host’s update cycle, before its template is rendered. When a host <serc-rod> has *for, it clears its content, runs the host-level loop, and calls the internal template renderer once per iteration.

Execution model

Element-level *for:

  1. Sercrod locates the *for (or n-for) attribute on the element.
  2. It parses the expression into keyName, valName, modeWord ("in" or "of"), and srcExpr.
  3. It evaluates srcExpr in the current scope with { el: work, mode: "for" }.
  4. If the result is falsy, *for acts as an empty loop and renders nothing.
  5. For each entry in the collection (interpreted according to in or of):
    • Sercrod clones the entire element subtree with cloneNode(true).
    • It removes *for and n-for from the clone.
    • It merges the iteration variables into the scope for that clone.
    • It calls the internal element renderer on the clone.
  6. The clones are appended to the original parent in order.
  7. The original element is not appended; it serves only as the template.

Host-level *for on <serc-rod>:

  1. During an update, the host decides whether it should re-render.
  2. The host clears its current content (innerHTML = "").
  3. It determines the current top-level scope (_stage if a staging branch is active, otherwise _data).
  4. It reads the host’s *for or n-for expression and parses it with the same (key, value) in|of expr pattern.
  5. It evaluates the iterable expression with { el: this, mode: "update" }.
  6. It normalizes the result into [key, value] pairs, using a helper that:
    • Treats x in array with a single variable similar to x of array for backward compatibility (values rather than keys).
    • For objects, returns [key, value] pairs for both of and in, but emphasizes of as the clearer option when you need (key, value).
  7. For each [k, v] pair:
    • If both keyName and valName are present, the host calls its template renderer with { ...scope, [keyName]: k, [valName]: v }.
    • If only valName is present, it renders with { ...scope, [valName]: v }.
  8. The result is a single <serc-rod> instance whose children are repeated blocks rendered from the host’s template.

Variable creation and scope layering

Element-level *for:

Host-level *for:

Guidelines:

Parent access

*for does not introduce a dedicated parent reference, but you can still access parent data as usual:

Loop variables exist alongside these references and do not prevent you from reading outer scopes.

Use with conditionals and loops

You can safely combine *for with other directives when they are placed thoughtfully:

Use with templates and *include

*for works well with templates and *include:

Comparison with *each

Both *for and *each iterate collections, but they operate on different structural levels:

Guideline:

Host-level *for on (advanced)

Placing *for directly on a Sercrod host is an advanced but powerful pattern:

Basic example:

<serc-rod id="host" *for="user of users" data='{
  "users": [
    { "name": "Alice", "age": 30 },
    { "name": "Bob",   "age": 25 }
  ]
}'>
  <section class="user-card">
    <h2 *print="user.name"></h2>
    <p *print="user.age + ' years old'"></p>
  </section>
</serc-rod>

Behavior:

Notes on semantics:

Best practices

Additional examples

Iterating over an object map with both key and value:

<serc-rod id="app" data='{
  "users": {
    "u1": { "name": "Alice" },
    "u2": { "name": "Bob" }
  }
}'>
  <ul>
    <li *for="(id, user) of users">
      <strong *print="id"></strong>
      <span *print="user.name"></span>
    </li>
  </ul>
</serc-rod>

Using *for on table rows:

<serc-rod id="table" data='{
  "rows": [
    { "id": 1, "name": "Alpha" },
    { "id": 2, "name": "Beta" }
  ]
}'>
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <tr *for="row of rows">
        <td *print="row.id"></td>
        <td *print="row.name"></td>
      </tr>
    </tbody>
  </table>
</serc-rod>

Notes