Computed Properties

v2 replaces most standalone computed properties with @expr: in RTML templates. For complex logic, use Go methods.


@expr: in Templates

Inline computed expressions that re-evaluate when their signal dependencies change:

<p>Doubled: @expr:Count.Get * 2</p>
<p>Positive: @expr:Count.Get > 0</p>
<p>Greeting: @expr:Name.Get + "!"</p>

Any Get() call inside @expr: creates a dependency. When the signal updates, only the affected expression re-renders.

Inline Conditionals (Ternary)

Use then ... else for inline conditionals — reads naturally in templates:

<p>Status: @expr:Active.Get then "Online" else "Offline"</p>
<p>Tier: @expr:Count.Get > 10 then "high" else "low"</p>

Nested:

<p>Size: @expr:Count.Get > 100 then "XL" else Count.Get > 50 then "L" else "M"</p>

Legacy ? : syntax also works:

<p>Status: @expr:Active.Get ? "Online" : "Offline"</p>

Prefer then ... else for readability.


Complex Logic in Go Methods

When @expr: isn’t enough, define a method on the struct:

type Stats struct {
    *core.HTMLComponent
    Scores *t.String
}

In RTML:

<p>Average: {Average}</p>

The {Method} syntax calls the method and injects the result.


When to Use What

Approach Use for
@expr: Simple arithmetic, comparisons, string concatenation
Go method + {Method} Multi-step logic, loops, error handling
state.Effect Side effects that react to signal changes

Effects for Derived State

When you need to react to changes with side effects (logging, syncing, DOM manipulation), use state.Effect:

state.Effect(func() func() {
    val := count.Get()
    fmt.Println("count changed to", val)
    return nil
})

Effects re-run when any signal read inside them changes. Return a cleanup function if needed.