sercrod

*each

Summary

*each repeats the children of a single host element for each entry in a list, object, or other iterable. The host element itself is rendered exactly once and acts as a container. The directive understands JavaScript-like in and of loop syntax and has an alias n-each.

Use *each when you want one structural wrapper (such as <ul>, <tbody>, or <div>) whose contents are repeated.

Important restriction:

Basic example

A simple list:

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

Behavior:

Behavior

Alias:

Expression syntax

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

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

Supported and recommended patterns:

Collection evaluation:

Value semantics

For modeWord = "of":

For modeWord = "in":

Recommendation:

Evaluation timing

*each participates in Sercrod’s structural evaluation order:

Execution model

Conceptually, the runtime behaves like this when it encounters *each:

  1. Evaluate the expression on *each to obtain a collection (iterable).
    • If the result is falsy, treat it as an empty collection and stop.
  2. Create a shallow clone of the host element as a container.
    • The tag name and all attributes are copied.
    • The *each / n-each attribute is removed from the clone.
  3. Take the original child nodes of the host as the template body.
  4. For each entry in the collection:
    • Prepare a per-iteration scope that merges:
      • The effective parent scope.
      • The per-iteration variables (for example item, index, key, value).
    • Render each original child node with this scope into the container.
  5. Append the container to the parent of the original host.
    • The original host node is not appended.

On re-renders:

Variable creation and scope layering

Inside the body of *each:

Guidelines:

Parent access

*each does not introduce a separate parent object, but parent data remain available through the normal Sercrod scope model:

The only additional names introduced by *each are the loop variables themselves.

Use with conditionals and loops

*each is designed to compose with other directives when they target different layers:

Use with templates, *include and *import

*each, *include, and *import are all structural directives that control the children of a host element, but in different ways:

Because all of these directives want to own the host’s children, putting them on the same element is not supported.

Invalid patterns:

<ul *each="item of items" *include="'user-item'">
  <!-- This combination is not supported -->
</ul>

<ul *each="item of items" *import="'user-item'">
  <!-- This combination is also not supported -->
</ul>

Reasons:

Supported patterns:

If your project wraps *include with other helpers, or defines *import as such a helper, the same restriction applies: do not put those helpers on the same element as *each.

Comparison with *for

Both *for and *each iterate collections, but they do so at different structural levels.

Recommendations:

Best practices

Additional examples

Iterating over an object map:

<serc-rod id="app" data='{
  "users": {
    "u1": { "name": "Alice" },
    "u2": { "name": "Bob" }
  }
}'>
  <dl *each="(id, user) of users">
    <dt *print="id"></dt>
    <dd *print="user.name"></dd>
  </dl>
</serc-rod>

Using *each on <tbody>:

<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 *each="row of rows">
      <tr>
        <td *print="row.id"></td>
        <td *print="row.name"></td>
      </tr>
    </tbody>
  </table>
</serc-rod>

Notes