sercrod

*elseif

Summary

*elseif defines an else-if branch inside a *if / *elseif / *else chain. Only one branch of the chain is rendered. The attribute form n-elseif is available and behaves identically.:contentReference[oaicite:0]{index=0}

The short built-in manual text describes it as:

Description

*elseif is a structural directive that participates in a sibling chain together with *if and *else. The chain is evaluated from left to right:

The engine guarantees that at most one branch of a chain is rendered. All decisions are made at the head *if node; each branch is then cloned or skipped as needed.:contentReference[oaicite:4]{index=4}

Basic example

<ul>
  <li *if="score >= 90">Grade A</li>
  <li *elseif="score >= 80">Grade B</li>
  <li *elseif="score >= 70">Grade C</li>
  <li *else>Grade F</li>
</ul>

In this example:

Semantically it works like a classic if / else if / else chain in JavaScript.:contentReference[oaicite:5]{index=5}

Behavior

Chain formation (how *elseif joins *if)

*elseif never works alone. It must be part of a chain headed by a *if (or n-if) on a preceding sibling:

If Sercrod cannot find a preceding *if for a *elseif (or *else), that element is treated as an invalid chain and is completely ignored during rendering.:contentReference[oaicite:8]{index=8}

Important Sercrod-specific constraint

Because chain membership is determined only through adjacent conditional siblings:

For example:

<div *if="mode === 'view'">View</div>
<p>separator</p>
<div *elseif="mode === 'edit'">Edit</div>

Here the second div is not part of the first *if chain because the <p> in between does not have conditional attributes. The *elseif cannot find a valid *if head and is therefore ignored.

Head-only evaluation

Once the head *if is known, Sercrod enforces the following rule:

This guarantees that the chain is evaluated exactly once, from its head.

Collecting the chain

Starting from the head *if, Sercrod walks to the right through sibling elements and collects all consecutive conditional siblings belonging to the same chain:

If the collected list is empty (which should not normally happen once a head is found), nothing is rendered.:contentReference[oaicite:12]{index=12}

Branch selection and *elseif conditions

Once Sercrod has the ordered list of branches, it selects exactly one branch:

  1. For each branch in order (if, then zero or more elseifs, then optional else):
    • Sercrod starts from the current effective scope (effScope).
    • If the branch element has *let / n-let, Sercrod creates a new branch-local scope that inherits from effScope, evaluates the *let code into this new scope, and uses it as branchScope for this branch only.
  2. If the branch type is "else":
    • It is selected only if no previous if / elseif was selected.
    • After selecting else, Sercrod stops looking at later branches.:contentReference[oaicite:15]{index=15}
  3. If the branch type is "if" or "elif":
    • Sercrod chooses the correct attribute name:
      • For "if": *if or n-if.
      • For "elif": *elseif or n-elseif.
    • It reads the expression string from that attribute. Empty strings are treated as “no condition” and will not match.
    • If there is a non-empty expression, it evaluates the condition via the internal _eval_cond helper on the branchScope.
    • If _eval_cond returns true, this branch is selected and no further branches are considered.

If no branch is selected (all conditions are falsy and there is no *else), nothing is rendered for this chain.

Rendering the chosen branch

When a branch (which may be *elseif) has been chosen:

As a result, the output DOM contains only the chosen branch, without *if, *elseif, *else, or branch-local *let attributes.

n-elseif

The n-elseif attribute is a direct alias of *elseif:

Evaluation timing

*elseif conditions are evaluated during the structural rendering phase of renderNode, after *let and *global have updated the effective scope but before other structural directives like *switch, *each, and *for run on the same host node.

Condition evaluation uses _eval_cond, which wraps the general eval_expr helper:

This means *elseif="flag" and *elseif="'false'" behave differently: flag depends on the runtime value of flag, but the literal string "false" is considered falsy by the helper.

Execution model

Sercrod’s overall update flow re-renders the host’s children from the stored template on each update call.:contentReference[oaicite:26]{index=26} Within that flow, a *if / *elseif / *else chain is a structural (“returning”) directive group:

The clone of the chosen branch then runs all non-structural directives (such as *print, :class, event bindings, etc.) as part of regular element rendering.

Variable creation

*elseif itself does not create variables, but it interacts closely with *let on the same element:

Example:

<div *if="user">
  <p *let="full = user.first + ' ' + user.last">
    Hello, %full%!
  </p>
</div>
<div *elseif="guest">
  <p *let="label = 'Guest ' + guest.id">
    Hello, %label%!
  </p>
</div>
<div *else>
  <p>Hello, anonymous visitor.</p>
</div>

In this pattern, full and label exist only inside their respective branches.

Scope layering

*elseif uses the same scope layering as *if:

If a *if / *elseif / *else group is nested inside loops (*for, *each) or inside other components, the loop/parent scopes are simply part of the normal scope chain and are available to the *elseif condition.

Parent access

Because eval_expr injects $parent into the evaluation scope when it is not already defined, *elseif conditions can safely refer to properties of the parent Sercrod host’s data.

Typical patterns:

<div *if="$parent.mode === 'edit'">Edit in parent context</div>
<div *elseif="$parent.mode === 'view'">View in parent context</div>
<div *else>Other mode</div>

This works regardless of whether the chain is inside loops, nested components, or other control structures.

Use with conditionals and loops

*elseif is designed to be combined with other control structures by nesting, not by mixing multiple structural directives on the same element.

Common patterns include:

In these patterns, the outer constructs (*for, *switch) decide which subtree is rendered, and the inner *if chain refines the result inside that subtree. The scopes provided by the outer structures are available to the *elseif conditions via normal scope inheritance.

Best practices

Examples

Example 1: Multi-mode display
<div>
  <p *if="mode === 'view'">Viewing %item.title%</p>
  <p *elseif="mode === 'edit'">Editing %item.title%</p>
  <p *elseif="mode === 'create'">Creating a new item</p>
  <p *else>Please select a mode.</p>
</div>

Behavior:

Example 2: Branch-local *let
<section>
  <h2>Order summary</h2>

  <p *if="order">
    <span *let="total = order.price * order.qty">
      Total: %total%
    </span>
  </p>

  <p *elseif="draft">
    <span *let="estimate = draft.price * draft.qty">
      Estimated total: %estimate%
    </span>
  </p>

  <p *else>
    No order or draft found.
  </p>
</section>

Here:

Example 3: Avoiding invalid chains
<div *if="status === 'ok'">OK</div>
<div *elseif="status === 'warn'">Warning</div>

<!-- This element breaks the chain -->
<hr>

<div *elseif="status === 'error'">Error</div>
<div *else>Unknown</div>

In this layout:

To fix this, keep the branches adjacent:

<div *if="status === 'ok'">OK</div>
<div *elseif="status === 'warn'">Warning</div>
<div *elseif="status === 'error'">Error</div>
<div *else>Unknown</div>

<hr>

Notes