Conditional Rendering

Conditional blocks let parts of a template appear only when the data supports them. You wrap a region of the document in {% if condition %} ... {% endif %} and AdviceDocs decides at document-fill time whether to keep or drop that region. Anything inside a conditional block is also flagged as out of scope when the condition is false, so the user is never asked to fill data that won’t appear in the final document.

How conditional blocks are written

Conditional syntax follows Jinja2. The full set of forms below is supported by the template parser.

Plain if / endif

Plain if
{% if has_partner %}
  Partner name: {{ partner.name }}
{% endif %}

if / else

if / else
{% if is_couple %}
  This advice applies to both members of the couple.
{% else %}
  This advice applies to a single client.
{% endif %}

if / elif / else

if / elif / else
{% if risk_profile == "Conservative" %}
  Conservative recommendations apply.
{% elif risk_profile == "Balanced" %}
  Balanced recommendations apply.
{% elif risk_profile == "Growth" %}
  Growth recommendations apply.
{% else %}
  Default risk recommendations apply.
{% endif %}

Negation, boolean composition, comparisons, tests

The expression inside an if can use any of the standard Jinja2 operators.

  • Negation{% if not insurance %}
  • Boolean composition{% if has_partner and partner.is_employed %}, {% if has_super or has_smsf %}
  • Comparisons==, !=, <, >, <=, >=
  • Membershipin, not in
  • Testsis defined, is none, is not none, is true, is false
  • Truthy checks{% if amount %} evaluates to true for non-zero numbers, non-empty strings, non-empty lists, and so on.
Expression examples
{% if amount > 1000 %} ... {% endif %}
{% if status == "approved" %} ... {% endif %}
{% if client.age >= 65 %} ... {% endif %}
{% if not insurance %} ... {% endif %}
{% if has_partner and partner.has_employment %} ... {% endif %}
{% if risk_profile in ["Growth", "Aggressive"] %} ... {% endif %}
{% if recommended_amount is defined %} ... {% endif %}
{% if existing_plan is none %} ... {% endif %}

Comparisons can target any combination of fields, nested fields, string literals, and numeric literals. The left-hand side is treated as the condition field and is what gets recorded as the dependency for any nested fields.

Table-cell and table-row conditionals

Word tables can’t cleanly host a regular {% if %} block, so AdviceDocs adds two custom tags that the parser normalises into standard if-blocks before it walks the AST:

  • Table cell{% tc if condition %} ... {% endtc %} hides the cell’s content (or the whole column) when the condition is false.
  • Table row{% tr if condition %} ... {% endtr %} hides the entire row when the condition is false.
Table conditionals
{% tr if has_super %}
  | Super     | {{ super_balance }} |
{% endtr %}

{% tc if show_price %}
  {{ price }}
{% endtc %}

Behaviour is identical to {% if %} — the same operators, the same dependency tracking. Use tr/tc only when the conditional region sits inside a Word table; everywhere else, plain {% if %} works fine.

How condition dependencies are tracked

On upload, AdviceDocs walks the template’s AST and stores a list of conditions against every field that lives inside a conditional block. This list is the field’s condition_dependencies.

Outer-to-inner ordering

Dependencies are recorded outermost first, innermost last. Nested blocks accumulate — a field inside two nested ifs gets both conditions.

Two nested conditions
{% if has_partner %}
  {% if partner.has_employment %}
    {{ partner.employer }}
  {% endif %}
{% endif %}

# partner.employer.condition_dependencies = ["has_partner", "partner.has_employment"]

Negation is recorded as ! prefix

When the condition is {% if not X %}, the stored dependency is !X, so the truthy/falsy direction is preserved.

Negated condition
{% if not insurance %}
  {{ insurance_not_scope_reason }}
{% endif %}

# insurance_not_scope_reason.condition_dependencies = ["!insurance"]

Compound conditions store the primary field

For {% if X and Y %} or {% if X or Y %}, the parser records the left-hand operand (X) as the condition field. The right-hand side is parsed but not stored as a dependency.

What happens at document-fill time

  • Stage 1 of extraction evaluates each field’s condition_dependencies against the just-extracted data.
  • If any dependency evaluates false, the field is marked out_of_scope = TRUE and its value is left null.
  • Subsequent extraction stages skip out-of-scope fields entirely — no LLM calls are spent on data that won’t appear.
  • The field-review UI hides out-of-scope fields, so the user is never asked to fill them.
  • At render time, Jinja2 also evaluates the {% if %} block and drops the region from the document.

Visual cue in the editor

In the template editor and the field review UI, fields with conditions display a small orange badge for each dependency, e.g. {{has_partner}} or {{!insurance}}. The badge tooltip reads “Depends on [field] being truthy”, making it easy to trace why a field appeared or disappeared.

Nested if blocks

Nesting works as you’d expect. There is no fixed depth limit; conditions accumulate in outer-to-inner order, and a child field is only in scope when every ancestor condition is true.

Triple-nested conditions
{% if has_partner %}
  {% if partner.has_super %}
    {% if partner.super.balance > 100000 %}
      {{ partner.super.recommended_strategy }}
    {% endif %}
  {% endif %}
{% endif %}

Other control structures

Alongside {% if %} blocks, AdviceDocs supports a small subset of Jinja2.

  • Supported{% for %} loops (with {% else %} for the empty case), {% tr for %} for table-row loops.
  • Not supported{% set %}, {% block %}, {% include %}, {% import %}, {% macro %}, and Jinja2 filters such as {{ x | upper }}. (Use {{ X }} in ALL CAPS to force uppercase output instead.)

Common pitfalls

Missing endif

Every {% if %} needs a matching {% endif %} and every {% tc if %} needs {% endtc %}, every {% tr if %} needs {% endtr %}. An unbalanced block raises a Jinja2 syntax error at upload time and the field list won’t generate.

Use == not =

Comparisons use the double-equals operator. {% if status == "approved" %} is correct; {% if status = "approved" %} is a syntax error.

Curly quotes from Word

Word silently converts straight quotes " to curly quotes “ ”. AdviceDocs normalises these for you on upload, but you can avoid the warning by typing comparisons in a plain-text editor or by toggling off Word’s smart-quote autocorrect.

Typo: {{%endif

Writing {{%endif%}} (double curly instead of curly-percent) is a surprisingly common typo. The parser detects this specific case and returns a friendly error pointing at the offending line.

Compound conditions only track the left operand

For {% if X and Y %}{{ inner }}{% endif %}, only X is stored as the condition dependency on inner. If you rely on Y driving scope behaviour at fill time, prefer nesting two if-blocks instead so each condition is recorded explicitly.

Syntax to copy

Drop these into a template document and adapt the field names and literals to your data.

Existence / truthy checks
{% if has_partner %} ... {% endif %}
{% if partner.is_employed %} ... {% endif %}
{% if not insurance %} ... {% endif %}
{% if recommended_amount is defined %} ... {% endif %}
{% if existing_plan is none %} ... {% endif %}
String comparisons
{% if status == "approved" %} ... {% endif %}
{% if risk_profile != "Conservative" %} ... {% endif %}
{% if risk_profile in ["Growth", "Aggressive"] %} ... {% endif %}
Numeric comparisons
{% if amount > 1000 %} ... {% endif %}
{% if client.age >= 65 %} ... {% endif %}
{% if balance < recommended_minimum %} ... {% endif %}
Boolean composition
{% if has_partner and partner.has_employment %} ... {% endif %}
{% if has_super or has_smsf %} ... {% endif %}
{% if not (status == "rejected") %} ... {% endif %}
if / else / elif
{% if is_couple %}
  Couple advice
{% else %}
  Single advice
{% endif %}

{% if risk_profile == "Conservative" %}
  Conservative recommendations
{% elif risk_profile == "Balanced" %}
  Balanced recommendations
{% else %}
  Default recommendations
{% endif %}
Table conditionals
{% tr if has_super %}
  | Super | {{ super_balance }} |
{% endtr %}

{% tc if show_price %}
  {{ price }}
{% endtc %}