Skip to content

oneVcard Template Engine


The oneVcard Template Engine is available at selected locations, allowing you to enrich your content with dynamic data.

Simple Placeholders

A field name in double curly braces is replaced by its corresponding value.

{{placeholder}}

Example:

Data:

{ "firstName": "Max", "lastName": "Doe" }

Template:

Hello {{firstName}} {{lastName}}!

Result:

Hello Max Doe!

Missing Values

If a placeholder finds no value in the data, it is replaced by an empty string.

Hello {{name}}! → Hello !

Path Resolution

Placeholders can access nested fields in objects and arrays.

Nested Objects

Use a dot (.) as a separator:

{{user.address.city}}

Data:

{
"user": {
"address": {
"city": "Munich"
}
}
}

Result: Munich

Arrays by Index

Arrays are accessed using zero-based indices:

{{contacts[0].name}}
{{contacts[1].email}}

Data:

{
"contacts": [
{ "name": "Anna", "email": "anna@example.com" },
{ "name": "Bob", "email": "bob@example.com" }
]
}

Result: Anna / bob@example.com

Array Filters

You can filter an array by a specific field and then access the result:

{{contacts(type=billing_address)[0].name}}

This filters the contacts array for all entries where type === "billing_address" and returns the first match.

Optional Blocks

Optional blocks are written in double square brackets: [[ ... ]]

[[Street: {{address.street}}]]
[[ZIP: {{address.zipCode}}]]

Data:

{ "address": { "street": "Sample Street 1" } }

Result:

Street: Sample Street 1

The ZIP block is omitted entirely because address.zipCode is not present.

Multiple Placeholders in One Block

All placeholders in a block must be present for the block to be rendered:

[[{{firstName}} {{lastName}}]]

Only when both fields are present will the block appear.

Conditions

Conditions allow you to show or hide content depending on the data.

Basic Structure

{#if condition}
Content
{/if}
{#if condition}
Content
{:else}
Fallback
{/if}
{#if condition1}
Content 1
{:else if condition2}
Content 2
{:else}
Fallback
{/if}

Truthy/Falsy Values

When simply checking for the presence or truthiness of a field:

ValueResult
true, "true", non-empty stringtrue
non-empty arraytrue
false, "false", 0, ""false
missing / null / undefinedfalse
{#if user.active}Account is active{:else}Account locked{/if}

Comparison Operators

OperatorMeaning
==equal
!=not equal
>greater than
<less than
>=greater than or equal
<=less than or equal
{#if user.age >= 18}Adult{:else}Minor{/if}
{#if user.role == 'admin'}Administrator access{/if}
{#if status != 'locked'}Access allowed{/if}

Strings in conditions are enclosed in single or double quotes:

{#if country == "US"}Welcome to the United States{/if}
{#if country == 'GB'}Welcome to the United Kingdom{/if}

Logical Operators

Conditions can be combined with && (AND) and || (OR):

{#if active && age >= 18}Access granted{/if}
{#if role == 'admin' || role == 'manager'}Management{/if}
{#if a || b || c}At least one applies{/if}

Grouping

Use parentheses to define the order of evaluation:

{#if (role == 'admin' || role == 'editor') && active}Active editor{/if}
{#if age >= 18 && (member || promo)}Discount available{/if}

Block Functions

Block functions wrap content and transform or control its output.

{{#function attribute="value"}}
Content
{{/function}}

join

Joins multiple optional blocks with a delimiter. Blocks whose placeholders have no value are automatically skipped.

Attributes:

AttributeDescriptionDefault
delimiterSeparator between blocks""
prefixText before the result""
suffixText after the result""

Example - address line:

{{#join delimiter=", "}}
[[{{street}}]]
[[{{zipCode}} {{city}}]]
[[{{country}}]]
{{/join}}

Data:

{ "street": "Sample Street 1", "city": "Munich" }

Result: Sample Street 1, Munich

zipCode and city are missing. Their blocks are skipped — no double commas.

Example - with prefix and suffix:

{{#join delimiter=" · " prefix="[" suffix="]"}}
[[{{tag1}}]][[{{tag2}}]][[{{tag3}}]]
{{/join}}

Data:

{ "tag1": "Invoice", "tag3": "Urgent" }

Result: [Invoice · Urgent]

Line break as delimiter:

Use \n for a line break:

{{#join delimiter="\n"}}[[{{line1}}]][[{{line2}}]][[{{line3}}]]{{/join}}

uppercase

Converts all content to uppercase.

{{#uppercase}}{{salutation}} {{lastName}}{{/uppercase}}

Data:

{ "salutation": "Mr.", "lastName": "Miller" }

Result: MR. MILLER

format

Formats a value according to a specific style.

Attributes:

AttributeDescription
styleFormatting style: "phoneNumber" or "date"

Phone Number Formatting (style="phoneNumber")

Formats a phone number into international format.

AttributeDescriptionDefault
countryCountry code (ISO 3166-1) for numbers without a prefixnone
{{#format style="phoneNumber"}}{{phoneNumber}}{{/format}}

Numbers with an international prefix (+49, +1, +44, …) are automatically assigned to the correct country — no country attribute needed:

+491782367141 → +49 178 2367141
+12025550123 → +1 202 555 0123
+447911123456 → +44 7911 123456

Numbers without a prefix require the country attribute:

{{#format style="phoneNumber" country="US"}}{{phoneNumber}}{{/format}}
2025550123 → +1 202 555 0123

If the number cannot be parsed, the original value is returned unchanged.

Date Formatting (style="date")

Formats a date according to a pattern or locale.

AttributeDescriptionDefault
patternOutput format (token pattern, see below)Locale-dependent
localeLanguage/region format for output without pattern"de-DE"
inputFormatInput format when the value is not an ISO date (token pattern)automatic
Pattern Tokens
TokenDescriptionExample
yyyy4-digit year2025
yy2-digit year25
MMMonth (2 digits)06
ddDay (2 digits)15
HHHour (24h, 2 digits)14
mmMinute (2 digits)30
ssSecond (2 digits)00
MMMMMonth name (written out)June
EEEDay of week (short)Mon.
EEEEDay of week (written out)Monday

Examples:

{{#format style="date" pattern="MM/dd/yyyy"}}{{createdAt}}{{/format}}

Input: 2025-06-15 → Output: 06/15/2025

{{#format style="date" pattern="MM/dd/yyyy HH:mm"}}{{createdAt}}{{/format}}

Input: 2025-06-15T14:30:00 → Output: 06/15/2025 14:30

{{#format style="date" pattern="EEEE, MMMM dd, yyyy" locale="en-US"}}{{date}}{{/format}}

Input: 2025-06-15 → Output: Sunday, June 15, 2025

Input with Custom Format (inputFormat)

If your data does not contain an ISO date but e.g. 06/15/2025, use inputFormat:

{{#format style="date" inputFormat="MM/dd/yyyy" pattern="yyyy-MM-dd"}}{{date}}{{/format}}

Input: 06/15/2025 → Output: 2025-06-15

Inputs are parsed in this order:

  1. Custom inputFormat (if specified)
  2. ISO 8601 (2025-06-15 or 2025-06-15T14:30:00Z)
  3. Unix timestamp in milliseconds

replace

Replaces all occurrences of a text with another.

Attributes:

AttributeDescription
fromThe text to be replaced
toThe replacement text
{{#replace from="Inc." to="Corp."}}{{company}}{{/replace}}

Data:

{ "company": "Sample Inc." }

Result: Sample Corp.

Deleting text (replacement with empty string):

{{#replace from=" " to=""}}{{productCode}}{{/replace}}

Input: AB 1234 CD → Output: AB1234CD

each

Iterates over an array or object and outputs the content for each element.

Attributes:

AttributeDescriptionDefault
dataPath to the array or object-
asName of the loop variableentry

Array of Objects

{{#each data=users as="user"}}
- {{user.firstName}} {{user.lastName}}
{{/each}}

Data:

{
"users": [
{ "firstName": "Anna", "lastName": "Smith" },
{ "firstName": "Bob", "lastName": "Miller" }
]
}

Result:

- Anna Smith
- Bob Miller

Conditions within each

You can use {#if} inside {{#each}}. The condition is evaluated with the data of the current element:

{{#each data=users as="user"}}
{#if user.active}✓ {{user.firstName}}{:else}✗ {{user.firstName}}{/if}
{{/each}}

Optional Blocks within each

Optional blocks [[ ]] also work inside the loop:

{{#each data=contacts as="k"}}
[[{{k.firstName}} {{k.lastName}}]]
{{/each}}

Only contacts where both fields are present will appear in the output.

Iterating Objects

For objects, each key-value pair is passed as a two-part element:

  • entry.0 → the key
  • entry.1 → the value
{{#each data=properties as="e"}}
{{e.0}}: {{e.1}}
{{/each}}

Data:

{ "properties": { "color": "Blue", "size": "XL" } }

Result:

color: Blue
size: XL

Accessing Outer Data

Inside the loop, you also have access to all fields outside the array:

{{#each data=articles as="a"}}
{{a.name}} - Currency: {{currency}}
{{/each}}

Pipe Syntax

The pipe syntax is a more compact alternative to block functions when you want to transform a single value. Multiple pipes can be chained.

{{placeholder | function}}
{{placeholder | function(attribute="value")}}
{{placeholder | function1 | function2}}

Available Pipe Functions

FunctionDescription
uppercaseConverts to uppercase
format(...)Formats (date, phone number)
replace(...)Replaces text

Examples:

{{name | uppercase}}

max doeMAX DOE

{{phoneNumber | format(style="phoneNumber")}}

+12025550123+1 202 555 0123

{{date | format(style="date" pattern="MM/dd/yyyy")}}

2025-06-1506/15/2025

{{articleName | replace(from=" " to="_") | uppercase}}

Article NameARTICLE_NAME

Pipes in Optional Blocks

Pipes also work inside [[ ]] blocks. Block validity is determined by the source value, not the formatted result:

[[{{phoneNumber | format(style="phoneNumber")}}]]

The block is omitted if phoneNumber is missing or empty, regardless of what the formatting would return.

Attributes in Pipe Functions

As with block functions, you can pass attributes by name or positionally (see Attributes - Named vs. Positional):

{{date | format(style="date" pattern="MM/dd/yyyy")}} ← named
{{date | format("date" pattern="MM/dd/yyyy")}} ← style positional
{{text | replace("old", "new")}} ← both positional

Global Variables

The system provides some built-in variables under the g. prefix.

g.now - Current Date and Time

g.now returns the current date and time at the moment the template is evaluated.

Formatting the output:

{{g.now | format(style="date" pattern="MM/dd/yyyy")}}

Output: 04/17/2026

{{g.now | format(style="date" pattern="MM/dd/yyyy HH:mm")}}

Output: 04/17/2026 09:45

Using in conditions (see next section):

{#if g.now < "2025-12-31"}Promotion still running{:else}Promotion ended{/if}

Date Comparisons

Date values can be compared directly in conditions. The system automatically recognizes ISO 8601 date strings and compares them correctly as points in time, not as strings.

Supported Date Formats in Conditions

FormatExample
ISO date"2025-12-31"
ISO date with time"2025-12-31T23:59:59"
ISO date with timezone"2025-12-31T23:59:59Z"

Examples

Checking a promotion period:

{#if g.now >= "2025-01-01" && g.now <= "2025-12-31"}
Promotion 2025 is active
{/if}

Checking an expiry date from data:

{#if contract.validUntil >= g.now}
Contract is valid
{:else}
Contract has expired
{/if}

Comparing two date fields:

{#if delivery.arrival < delivery.planned}
Delivered early
{:else if delivery.arrival == delivery.planned}
Delivered on time
{:else}
Delayed
{/if}

Attributes - Named vs. Positional

Attributes in block functions and pipes can be specified in two ways.

Named Attributes

The attribute name is specified explicitly. Order does not matter.

{{#format style="date" pattern="MM/dd/yyyy"}}{{date}}{{/format}}
{{#format pattern="MM/dd/yyyy" style="date"}}{{date}}{{/format}} ← equivalent

Positional Attributes

The value is specified in quotes without a key name. The order determines which parameter the value is assigned to.

{{#format "phoneNumber"}}{{phoneNumber}}{{/format}}
{{#format "date" pattern="MM/dd/yyyy"}}{{date}}{{/format}}

Positional attributes can be mixed with named ones. Named attributes always take precedence.

Positional Order per Function

FunctionPosition 0Position 1Position 2
formatstylelocale / countrypattern
replacefromto-

Short form (pipe):

{{phoneNumber | format("phoneNumber")}}
{{date | format("date" pattern="MM/dd/yyyy")}}
{{text | replace("old", "new")}}

Known Limitations

Nested {{#each}} Blocks

Multiple nested {{#each}} blocks are currently not supported. Only the outermost level is processed correctly.

{{#each data=categories as="cat"}}
{{#each data=cat.articles as="art"}} ← does not work
{{art.name}}
{{/each}}
{{/each}}

{#if} Outside of {{#each}} Content

If a condition references fields that only exist inside a {{#each}} loop, the condition must be placed inside the {{#each}} block, which is supported. Conditions that reference loop variables from outside are not possible.

Quick Reference

Syntax Overview

SyntaxDescription
{{field}}Simple placeholder
{{obj.field}}Nested field
{{arr[0].field}}Array access by index
{{arr(key=val)[0].field}}Array filter
[[...{{field}}...]]Optional block (omitted if empty)
{#if cond}...{/if}Condition
{#if cond}...{:else}...{/if}Condition with else
{#if cond}...{:else if cond2}...{:else}...{/if}Multi-condition
{{#join delimiter=","}}...{{/join}}Join blocks
{{#uppercase}}...{{/uppercase}}Uppercase
{{#format style="date" pattern="..."}}...{{/format}}Date formatting
{{#format style="phoneNumber"}}...{{/format}}Phone number formatting
{{#replace from="x" to="y"}}...{{/replace}}Replace text
{{#each data=list as="item"}}...{{/each}}Loop
{{field | function}}Pipe
{{field | function | function2}}Pipe chain
g.nowCurrent date/time

Comparison Operators

OperatorMeaning
==equal
!=not equal
>greater than
<less than
>=greater than or equal
<=less than or equal
&&logical AND
||logical OR

Date Tokens (Selection)

TokenOutput
yyyy2025
MM06
dd15
HH:mm14:30
MM/dd/yyyy06/15/2025
MMMM yyyyJune 2025
EEEE, MMMM dd, yyyySunday, June 15, 2025