TemplatePro Official Documentation
⭐ Updated 2025-01-28 to TemplatePro Language version 0.7.3.
Here’s an example of a dynamic web application powered by DMVCFramework, TemplatePro and HTMX.

TemplatePro is a modern and versatile templating engine designed to simplify the dynamic generation of HTML, email content, and text files. With a syntax inspired by popular templating systems such as Jinja and Smarty, TemplatePro offers powerful features, including conditional blocks, loops, template inheritance and support for JSON data. In this comprehensive guide, we’ll explore all features of TemplatePro, from basic syntax to advanced features like custom filters, JSON manipulation, and nullable types support.
✌️ Since version 0.7.0 TemplatePro is case insensitive in variable names and in statements casing as-well.
Quick Start Example
Here’s a typical utilization of a template:
program tproconsole;
{$APPTYPE CONSOLE}
uses
TemplatePro, // TemplatePro compiler and executor
System.Rtti, // required by TValue
System.SysUtils; // required by try..except block
// This is a custom filter
function AddSquareBrackets(
const aValue: TValue;
const aParameters: TArray<TFilterParameter>): TValue;
begin
Result := '[' + aValue.AsString + ']';
end;
procedure Main;
var
lCompiledTemplate: ITProCompiledTemplate;
lCompiler: TTProCompiler;
begin
lCompiler := TTProCompiler.Create();
try
var lTemplate := 'Hello {{:name|brackets}}! Today is {{:today|datetostr}}.';
// Template must be compiled before utilization
lCompiledTemplate := lCompiler.Compile(lTemplate);
// Compiled template can be saved and retrieved from a file.
// A compiled template can be executed only
// by the same version that produced the template itself.
// lCompiledTemplate.SaveToFile('template.tpc');
// lCompiledTemplate := TTProCompiledTemplate.CreateFromFile('template.tpc');
finally
lCompiler.Free;
end;
// Then, on the compiled template, you can define variables,
// datasets, list of objects and json objects to use while rendering
// the compiled template.
// In this case we use simple variables
lCompiledTemplate.SetData('name', 'Daniele Teti');
lCompiledTemplate.SetData('today', Date);
// Compiled template can also use "filters" defined
// as simple functions with a specific prototype.
// In this case we are using a simple filter which adds
// square brackets to the input value.
lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);
// The render method returns the result of
// the template execution as string
WriteLn(lCompiledTemplate.Render);
// Output: Hello [Daniele Teti]! Today is 2025-01-28.
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
By the end of this guide, you’ll have a comprehensive understanding of TemplatePro’s capabilities and how to use it to create dynamic, maintainable templates for various applications.
1. Variable Interpolation and Basic Syntax
At the core of TemplatePro is variable interpolation, allowing you to inject dynamic content directly into your templates using the {{:variable}} syntax.
Basic Variable Usage
Hello, {{:name}}!
Your age is {{:age}} years old.
Output (if name is “Daniele” and age is 45):
Hello, Daniele!
Your age is 45 years old.
Object Property Access
TemplatePro supports nested object property access using dot notation:
{{:user.profile.first_name}} {{:user.profile.last_name}}
Email: {{:user.contact.email}}
Accessing Array Elements
You can access array elements using index notation:
First item: {{:items[0]}}
Second item: {{:items[1]}}
Null and Undefined Variables
TemplatePro gracefully handles null or undefined variables by rendering them as empty strings:
This will be empty if undefined: {{:undefined_var}}
This handles nulls gracefully: {{:nullable_field}}
2. Conditional Logic with if/else
TemplatePro provides powerful conditional logic to control template rendering based on data conditions.
Basic Conditional Blocks
{{if user_logged_in}}
Welcome back, {{:username}}!
{{else}}
Please log in to continue.
{{endif}}
Truthiness Evaluation
TemplatePro evaluates different data types for truthiness:
- Strings: Empty strings are falsy, non-empty strings are truthy
- Numbers: Zero is falsy, non-zero is truthy
- Objects: Null objects are falsy, non-null objects are truthy
- Collections: Empty collections/datasets are falsy, non-empty are truthy
- Boolean: True/false values work as expected
{{if customers}}
We have {{:customer_count}} customers.
{{else}}
No customers found.
{{endif}}
{{if score}}
Your score: {{:score}}
{{else}}
No score recorded.
{{endif}}
Complex Conditional Expressions
You can use filters in conditional expressions for more complex logic:
{{if age|ge,18}}
You are an adult.
{{else}}
You are a minor.
{{endif}}
{{if username|contains,"admin"}}
Admin user detected.
{{endif}}
{{if password|eq,confirm_password}}
Passwords match.
{{else}}
Password confirmation failed.
{{endif}}
3. Looping with for .. in
The for .. in loop is a powerful construct that lets you iterate over collections such as JSON arrays, datasets, or lists of objects.
Basic Loop Structure
{{for person in people}}
- {{:person.first_name}} {{:person.last_name}}
{{endfor}}
Output (for a list of people):
- Daniele Teti
- Peter Parker
- Bruce Banner
Loop Control with continue
Skip iterations using the {{continue}} statement:
{{for product in products}}
{{if product.discontinued|eq,true}}
{{continue}}
{{endif}}
Product: {{:product.name}} - Price: ${{:product.price}}
{{endfor}}
Nested Loops
You can nest loops to iterate over collections within collections:
{{for person in people}}
{{:person.first_name}} {{:person.last_name}}
{{for phone in person.phones}}
- {{:phone.type}}: {{:phone.number}}
{{endfor}}
{{if person.addresses}}
Addresses:
{{for address in person.addresses}}
- {{:address.street}}, {{:address.city}} {{:address.zip}}
{{endfor}}
{{endif}}
{{endfor}}
Pseudo-Variables in Loops
Special pseudo-variables provide additional context during iteration:
@@index: Current iteration index (1-based)@@odd: True for odd-indexed items@@even: True for even-indexed items
{{for customer in customers}}
{{:customer.@@index}}. {{:customer.Name}}
{{if customer.@@odd}}
(Odd position - highlighted)
{{endif}}
{{if customer.@@even}}
(Even position - standard)
{{endif}}
{{endfor}}
Output:
1. Ford Motors
(Odd position - highlighted)
2. Ferrari SpA
(Even position - standard)
3. Lotus Cars
(Odd position - highlighted)
Empty Collection Handling
Combine loops with conditionals to handle empty collections:
{{if orders}}
{{for order in orders}}
Order #{{:order.id}}: {{:order.total|formatfloat,"$#,##0.00"}}
{{endfor}}
{{else}}
No orders found.
{{endif}}
4. Working with Datasets
TemplatePro has excellent support for Delphi datasets, making it perfect for database-driven applications:
{{if customers}}
<table>
<tr><th>Code</th><th>Name</th><th>City</th></tr>
{{for customer in customers}}
<tr>
<td>{{:customer.Code}}</td>
<td>{{:customer.Name}}</td>
<td>{{:customer.City}}</td>
</tr>
{{endfor}}
</table>
{{else}}
<p>No customers in database.</p>
{{endif}}
5. Built-in Filters
TemplatePro provides a comprehensive set of built-in filters for common data transformations.
Text Transformation Filters
Original: {{:name}}
Uppercase: {{:name|uppercase}}
Lowercase: {{:name|lowercase}}
Capitalize: {{:name|capitalize}}
Output (if name is “daniele teti”):
Original: daniele teti
Uppercase: DANIELE TETI
Lowercase: daniele teti
Capitalize: Daniele Teti
Padding Filters
Right padded: "{{:code|rpad,10}}"
Right padded with dashes: "{{:code|rpad,10,"-"}}"
Left padded: "{{:code|lpad,8}}"
Left padded with zeros: "{{:id|lpad,6,"0"}}"
Date and Time Filters
System format: {{:birth_date|datetostr}}
Custom format: {{:birth_date|datetostr,"dd/mm/yyyy"}}
DateTime: {{:created_at|datetimetostr,"yyyy-mm-dd hh:nn:ss"}}
ISO format: {{:timestamp|datetoiso8601}}
Numeric Filters
Formatted: {{:price|formatfloat,"$#,##0.00"}}
Percentage: {{:rate|formatfloat,"0.00%"}}
Scientific: {{:large_number|formatfloat,"0.00E+00"}}
Text Processing Filters
Truncated: {{:description|trunc,50}}
HTML encoded: {{:user_input|htmlencode}}
Version info: {{:""|version}}
Comparison Filters (for use in if statements)
{{if age|ge,18}}
Adult user
{{endif}}
{{if username|contains,"admin"}}
Administrator privileges
{{endif}}
{{if status|eq,"active"}}
User is active
{{endif}}
{{if price|lt,100}}
Budget-friendly option
{{endif}}
Complete Built-in Filters Reference:
| Filter Name | Description | Example |
|---|---|---|
uppercase |
Convert to uppercase | {{:name|uppercase}} |
lowercase |
Convert to lowercase | {{:name|lowercase}} |
capitalize |
Capitalize each word | {{:title|capitalize}} |
rpad,length[,char] |
Right-pad to length | {{:code|rpad,10,"-"}} |
lpad,length[,char] |
Left-pad to length | {{:id|lpad,6,"0"}} |
datetostr[,format] |
Format date | {{:date|datetostr,"dd/mm/yyyy"}} |
datetimetostr[,format] |
Format datetime | {{:datetime|datetimetostr}} |
datetoiso8601 |
ISO 8601 format | {{:date|datetoiso8601}} |
formatfloat,format |
Format numbers | {{:price|formatfloat,"$0.00"}} |
trunc,length |
Truncate text | {{:text|trunc,50}} |
htmlencode |
HTML encode | {{:input|htmlencode}} |
version |
TemplatePro version | {{""|version}} |
totrue |
Always true | {{:var|totrue}} |
tofalse |
Always false | {{:var|tofalse}} |
| Comparison Filters | ||
eq,value |
Equal to | {{if age|eq,25}} |
ne,value |
Not equal to | {{if status|ne,"inactive"}} |
gt,value |
Greater than | {{if score|gt,80}} |
ge,value |
Greater or equal | {{if age|ge,18}} |
lt,value |
Less than | {{if price|lt,100}} |
le,value |
Less or equal | {{if items|le,10}} |
contains,text |
Contains text | {{if name|contains,"John"}} |
icontains,text |
Case-insensitive contains | {{if email|icontains,"gmail"}} |
6. Custom Filters
TemplatePro allows you to define custom filters to extend functionality beyond the built-in set.
Filter Function Signatures
// Regular function
TTProTemplateFunction =
function(const aValue: TValue; const aParameters: TArray<TFilterParameter>): TValue;
// Anonymous method
TTProTemplateAnonFunction =
reference to function(const aValue: TValue; const aParameters: TArray<TFilterParameter>): TValue;
Simple Custom Filter Example
function AddSquareBrackets(const aValue: TValue;
const aParameters: TArray<TFilterParameter>): TValue;
begin
Result := '[' + aValue.AsString + ']';
end;
// Register the filter
lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);
Usage:
Original: {{:username}}
Bracketed: {{:username|brackets}}
Filter with Parameters
function RepeatText(const aValue: TValue;
const aParameters: TArray<TFilterParameter>): TValue;
var
lText: string;
lCount, i: Integer;
begin
lText := aValue.AsString;
lCount := aParameters[0].ParIntValue;
Result := '';
for i := 1 to lCount do
Result := Result + lText;
end;
// Register the filter
lCompiledTemplate.AddFilter('repeat', RepeatText);
Usage:
Repeated: {{:char|repeat,5}}
Advanced Filter with Multiple Parameters
function SubstringFilter(const aValue: TValue;
const aParameters: TArray<TFilterParameter>): TValue;
var
lText: string;
lStart, lLength: Integer;
begin
lText := aValue.AsString;
lStart := aParameters[0].ParIntValue;
if Length(aParameters) > 1 then
lLength := aParameters[1].ParIntValue
else
lLength := Length(lText) - lStart + 1;
Result := Copy(lText, lStart, lLength);
end;
// Register the filter
lCompiledTemplate.AddFilter('substr', SubstringFilter);
Usage:
Substring: {{:text|substr,1,10}}
From position: {{:text|substr,5}}
Using Variables as Filter Parameters
All filters support variables as parameters:
{{:message|truncate,max_length}}
{{:price|formatfloat,number_format}}
{{if score|gt,passing_grade}}
Congratulations!
{{endif}}
7. Template Functions
Functions are filters applied to empty values, useful for calculations and utility operations.
Built-in Function Usage
Current version: {{:|version}}
Random calculation: {{:|sum,10,20,30}}
String concatenation: {{:|concat,"Hello"," ","World"}}
Custom Function Example
function GenerateUUID(const aValue: TValue;
const aParameters: TArray<TFilterParameter>): TValue;
begin
if not aValue.IsEmpty then
raise ETProRenderException.Create('"GenerateUUID" is a function, not a filter');
Result := TGuid.NewGuid.ToString;
end;
// Register the function
lCompiledTemplate.AddFilter('uuid', GenerateUUID);
Usage:
New ID: {{:|uuid}}
8. Working with JSON Data
TemplatePro excels at handling JSON data, making it ideal for APIs and structured data.
Basic JSON Iteration
{{for person in people}}
{{:person.@@index}}) {{:person.first_name|uppercase}} {{:person.last_name|uppercase}}
Age: {{:person.age}}
{{if person.devices}}
Devices:
{{for device in person.devices}}
{{:device.@@index}}° {{:device.name}} ({{:device.type}})
{{endfor}}
{{endif}}
{{if person.car}}
Car: {{:person.car.brand}} {{:person.car.model|uppercase}}
{{endif}}
{{if person.@@odd}}
(This person is at an odd position)
{{endif}}
{{endfor}}
Complex JSON Structures
{{for order in orders}}
Order #{{:order.id}} - {{:order.date|datetostr}}
Customer: {{:order.customer.name}}
Items:
{{for item in order.items}}
- {{:item.product.name}}: {{:item.quantity}} x {{:item.price|formatfloat,"$0.00"}}
{{endfor}}
Total: {{:order.total|formatfloat,"$#,##0.00"}}
Status: {{:order.status|uppercase}}
{{if order.shipping_address}}
Shipping to:
{{:order.shipping_address.street}}
{{:order.shipping_address.city}}, {{:order.shipping_address.state}} {{:order.shipping_address.zip}}
{{endif}}
{{endfor}}
JSON Arrays and Objects
{{for category in categories}}
<h2>{{:category.name}}</h2>
{{if category.products}}
<ul>
{{for product in category.products}}
<li>
{{:product.name}} - {{:product.price|formatfloat,"$0.00"}}
{{if product.on_sale}}
<span class="sale">ON SALE!</span>
{{endif}}
</li>
{{endfor}}
</ul>
{{else}}
<p>No products in this category.</p>
{{endif}}
{{endfor}}
9. Template Inheritance
Template inheritance allows you to create reusable layouts and component hierarchies.
Base Template (base.tpro)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{block "title"}}Default Title{{endblock}}</title>
<link rel="stylesheet" href="/css/style.css">
{{block "extra_css"}}{{endblock}}
<meta name="description" content="{{block "meta_description"}}Default description{{endblock}}">
</head>
<body>
<header>
<nav>
{{block "navigation"}}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
{{endblock}}
</nav>
</header>
<main class="container">
{{block "breadcrumbs"}}{{endblock}}
<div class="content">
{{block "content"}}
<h1>Welcome</h1>
<p>This is the default content.</p>
{{endblock}}
</div>
<aside class="sidebar">
{{block "sidebar"}}{{endblock}}
</aside>
</main>
<footer>
{{block "footer"}}
<p>© 2025 My Website. All rights reserved.</p>
{{endblock}}
</footer>
{{block "extra_js"}}{{endblock}}
</body>
</html>
Child Template
{{extends "base.tpro"}}
{{block "title"}}{{:page_title}} - My Website{{endblock}}
{{block "meta_description"}}{{:page_description}}{{endblock}}
{{block "extra_css"}}
<link rel="stylesheet" href="/css/products.css">
{{endblock}}
{{block "breadcrumbs"}}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li class="active">{{:category_name}}</li>
</ol>
</nav>
{{endblock}}
{{block "content"}}
<h1>{{:category_name|capitalize}}</h1>
<p>{{:category_description}}</p>
{{if products}}
<div class="product-grid">
{{for product in products}}
<div class="product-card">
<img src="{{:product.image_url}}" alt="{{:product.name}}">
<h3>{{:product.name}}</h3>
<p class="price">{{:product.price|formatfloat,"$#,##0.00"}}</p>
{{if product.discount|gt,0}}
<span class="discount">{{:product.discount}}% OFF</span>
{{endif}}
<button class="add-to-cart" data-product-id="{{:product.id}}">
Add to Cart
</button>
</div>
{{endfor}}
</div>
{{else}}
<p class="no-products">No products found in this category.</p>
{{endif}}
{{endblock}}
{{block "sidebar"}}
<div class="category-sidebar">
<h3>Categories</h3>
<ul>
{{for cat in all_categories}}
<li>
<a href="/products/{{:cat.slug}}"
{{if cat.id|eq,current_category_id}}class="active"{{endif}}>
{{:cat.name}} ({{:cat.product_count}})
</a>
</li>
{{endfor}}
</ul>
</div>
{{endblock}}
{{block "extra_js"}}
<script src="/js/products.js"></script>
{{endblock}}
Template Inheritance Rules
- Single-level inheritance: Child templates can only extend one parent template (no multi-level inheritance)
- Block overriding: If a child defines a block that exists in the parent, it overrides the parent’s block
- Default blocks: If a child doesn’t define a block, the parent’s default content is used
- Ignored content: Any content outside of blocks in child templates is ignored
- Unknown blocks: Child blocks not defined in the parent are ignored
10. Template Inclusion
Use the {{include}} directive to modularize templates by splitting them into reusable components.
Basic Inclusion
{{include "header.tpro"}}
<main>
<!-- Main content here -->
<h1>{{:page_title}}</h1>
<p>{{:content}}</p>
</main>
{{include "footer.tpro"}}
Including with Subdirectories
{{include "partials/navigation.tpro"}}
{{include "components/product-card.tpro"}}
{{include "layouts/sidebar.tpro"}}
Modular Component Example
components/product-card.tpro:
<div class="product-card">
<img src="{{:product.image}}" alt="{{:product.name|htmlencode}}">
<h3>{{:product.name|htmlencode}}</h3>
<p class="description">{{:product.description|trunc,100|htmlencode}}</p>
<div class="price">
{{if product.sale_price}}
<span class="original-price">{{:product.price|formatfloat,"$0.00"}}</span>
<span class="sale-price">{{:product.sale_price|formatfloat,"$0.00"}}</span>
{{else}}
<span class="price">{{:product.price|formatfloat,"$0.00"}}</span>
{{endif}}
</div>
{{if product.in_stock}}
<button class="btn-primary">Add to Cart</button>
{{else}}
<button class="btn-disabled" disabled>Out of Stock</button>
{{endif}}
</div>
Main template:
{{include "components/header.tpro"}}
<div class="products-container">
{{for product in products}}
{{include "components/product-card.tpro"}}
{{endfor}}
</div>
{{include "components/footer.tpro"}}
11. Working with Nullable Types
TemplatePro has excellent support for Delphi’s nullable types, handling them gracefully in templates.
Nullable Variables
{{if user.middle_name}}
Full name: {{:user.first_name}} {{:user.middle_name}} {{:user.last_name}}
{{else}}
Name: {{:user.first_name}} {{:user.last_name}}
{{endif}}
{{if order.shipped_date}}
Shipped: {{:order.shipped_date|datetostr}}
{{else}}
Status: Processing
{{endif}}
{{if product.weight}}
Weight: {{:product.weight|formatfloat,"0.00"}} kg
{{endif}}
Nullable Numeric Values
{{if item.discount_percentage}}
Discount: {{:item.discount_percentage|formatfloat,"0.0"}}%
Final price: {{:item.final_price|formatfloat,"$0.00"}}
{{else}}
Price: {{:item.price|formatfloat,"$0.00"}}
{{endif}}
12. Advanced Examples
E-commerce Product Listing
{{extends "shop-base.tpro"}}
{{block "title"}}{{:category.name}} Products - Online Store{{endblock}}
{{block "content"}}
<div class="category-header">
<h1>{{:category.name|capitalize}}</h1>
<p>{{:category.description}}</p>
{{if products}}
<p class="product-count">
Showing {{:products|count}} of {{:total_products}} products
</p>
{{endif}}
</div>
{{if products}}
<div class="product-filters">
<select name="sort" onchange="updateSort(this.value)">
<option value="name">Sort by Name</option>
<option value="price_low">Price: Low to High</option>
<option value="price_high">Price: High to Low</option>
<option value="rating">Highest Rated</option>
</select>
<div class="price-filter">
<label>Max Price: {{:max_price|formatfloat,"$0"}}</label>
</div>
</div>
<div class="products-grid">
{{for product in products}}
<article class="product-item" data-product-id="{{:product.id}}">
<div class="product-image">
<img src="{{:product.main_image.url}}"
alt="{{:product.name|htmlencode}}"
loading="lazy">
{{if product.badge}}
<span class="product-badge {{:product.badge.type}}">
{{:product.badge.text|uppercase}}
</span>
{{endif}}
</div>
<div class="product-info">
<h3>
<a href="/product/{{:product.slug}}">
{{:product.name|htmlencode}}
</a>
</h3>
<div class="product-rating">
{{for star in product.rating_stars}}
<span class="star {{if star.filled}}filled{{endif}}">★</span>
{{endfor}}
<span class="rating-count">({{:product.review_count}})</span>
</div>
<p class="product-summary">
{{:product.short_description|trunc,100|htmlencode}}
</p>
<div class="product-price">
{{if product.sale_price}}
<span class="original-price">
{{:product.original_price|formatfloat,"$#,##0.00"}}
</span>
<span class="sale-price">
{{:product.sale_price|formatfloat,"$#,##0.00"}}
</span>
<span class="savings">
Save {{:product.savings|formatfloat,"$0.00"}}
</span>
{{else}}
<span class="price">
{{:product.price|formatfloat,"$#,##0.00"}}
</span>
{{endif}}
</div>
<div class="product-actions">
{{if product.in_stock}}
<button class="btn-add-cart"
data-product="{{:product.id}}"
onclick="addToCart(this)">
Add to Cart
</button>
{{if product.stock_level|le,5}}
<small class="stock-warning">
Only {{:product.stock_level}} left!
</small>
{{endif}}
{{else}}
<button class="btn-out-of-stock" disabled>
Out of Stock
</button>
<button class="btn-notify"
onclick="notifyWhenAvailable('{{:product.id}}')">
Notify When Available
</button>
{{endif}}
</div>
{{if product.features}}
<div class="product-features">
{{for feature in product.features}}
<span class="feature-tag">{{:feature.name}}</span>
{{endfor}}
</div>
{{endif}}
</div>
</article>
{{endfor}}
</div>
{{if has_more_products}}
<div class="pagination">
{{if current_page|gt,1}}
<a href="?page={{:prev_page}}" class="page-link">Previous</a>
{{endif}}
{{for page in page_numbers}}
{{if page.current}}
<span class="page-current">{{:page.number}}</span>
{{else}}
<a href="?page={{:page.number}}" class="page-link">
{{:page.number}}
</a>
{{endif}}
{{endfor}}
{{if current_page|lt,total_pages}}
<a href="?page={{:next_page}}" class="page-link">Next</a>
{{endif}}
</div>
{{endif}}
{{else}}
<div class="no-products">
<h2>No products found</h2>
<p>Try adjusting your search criteria or browse our other categories.</p>
<div class="suggested-categories">
<h3>You might be interested in:</h3>
<ul>
{{for suggestion in suggested_categories}}
<li>
<a href="/category/{{:suggestion.slug}}">
{{:suggestion.name}} ({{:suggestion.product_count}} products)
</a>
</li>
{{endfor}}
</ul>
</div>
</div>
{{endif}}
{{endblock}}
Email Template Example
{{extends "email-base.tpro"}}
{{block "subject"}}Order Confirmation #{{:order.number}}{{endblock}}
{{block "preheader"}}Your order has been confirmed and will be shipped soon.{{endblock}}
{{block "content"}}
<div class="email-header">
<h1>Thank you for your order!</h1>
<p>Hi {{:customer.first_name}}, your order has been confirmed.</p>
</div>
<div class="order-details">
<h2>Order Summary</h2>
<table class="order-table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{{for item in order.items}}
<tr>
<td>
<strong>{{:item.product.name}}</strong>
{{if item.variant}}
<br><small>{{:item.variant.name}}</small>
{{endif}}
</td>
<td>{{:item.quantity}}</td>
<td>{{:item.unit_price|formatfloat,"$0.00"}}</td>
<td>{{:item.total_price|formatfloat,"$0.00"}}</td>
</tr>
{{endfor}}
</tbody>
<tfoot>
<tr>
<td colspan="3"><strong>Subtotal:</strong></td>
<td><strong>{{:order.subtotal|formatfloat,"$0.00"}}</strong></td>
</tr>
{{if order.discount_amount|gt,0}}
<tr>
<td colspan="3">Discount ({{:order.discount_code}}):</td>
<td>-{{:order.discount_amount|formatfloat,"$0.00"}}</td>
</tr>
{{endif}}
<tr>
<td colspan="3">Shipping:</td>
<td>{{:order.shipping_cost|formatfloat,"$0.00"}}</td>
</tr>
<tr>
<td colspan="3">Tax:</td>
<td>{{:order.tax_amount|formatfloat,"$0.00"}}</td>
</tr>
<tr class="total-row">
<td colspan="3"><strong>Total:</strong></td>
<td><strong>{{:order.total|formatfloat,"$0.00"}}</strong></td>
</tr>
</tfoot>
</table>
</div>
<div class="shipping-info">
<h3>Shipping Information</h3>
<p>
<strong>{{:shipping.address.name}}</strong><br>
{{:shipping.address.street1}}<br>
{{if shipping.address.street2}}
{{:shipping.address.street2}}<br>
{{endif}}
{{:shipping.address.city}}, {{:shipping.address.state}} {{:shipping.address.zip}}<br>
{{:shipping.address.country}}
</p>
<p>
<strong>Shipping Method:</strong> {{:shipping.method.name}}<br>
<strong>Estimated Delivery:</strong> {{:shipping.estimated_delivery|datetostr,"MMM dd, yyyy"}}
</p>
</div>
<div class="next-steps">
<h3>What happens next?</h3>
<ol>
<li>We'll prepare your order for shipping</li>
<li>You'll receive a tracking number when your order ships</li>
<li>Your order will be delivered by {{:shipping.estimated_delivery|datetostr,"MMM dd"}}</li>
</ol>
</div>
<div class="customer-service">
<p>
Questions about your order? Contact our customer service team at
<a href="mailto:{{:company.support_email}}">{{:company.support_email}}</a>
or call {{:company.phone}}.
</p>
</div>
{{endblock}}
13. Performance Tips and Best Practices
Template Compilation
- Always compile templates once and reuse the compiled version
- Save compiled templates to files for better startup performance
- Use appropriate caching strategies for production environments
Filter Usage
- Use built-in filters when possible (they’re optimized)
- Minimize complex custom filters in loops
- Consider pre-processing data instead of complex template logic
JSON Data Handling
- Structure your JSON data to minimize nested loops
- Use appropriate data types to leverage TemplatePro’s type system
- Consider paginating large datasets
Template Organization
- Use template inheritance for consistent layouts
- Break large templates into smaller, reusable components
- Organize templates in logical directory structures
Error Handling
try
lCompiledTemplate := lCompiler.Compile(lTemplate);
lResult := lCompiledTemplate.Render;
except
on E: ETProCompilerException do
// Handle compilation errors
ShowMessage('Template compilation error: ' + E.Message);
on E: ETProRenderException do
// Handle rendering errors
ShowMessage('Template rendering error: ' + E.Message);
on E: Exception do
// Handle other errors
ShowMessage('Unexpected error: ' + E.Message);
end;
Conclusion
TemplatePro is a comprehensive and powerful templating engine that provides developers with the flexibility and control needed for modern application development. Its rich feature set includes:
- Intuitive Syntax: Clean, readable template syntax inspired by popular engines
- Powerful Logic: Comprehensive conditional statements and looping constructs
- Template Inheritance: Reusable layouts and component hierarchies
- Extensive Filters: Rich set of built-in filters plus custom filter support
- JSON Excellence: First-class support for complex JSON data structures
- Type Safety: Excellent handling of Delphi’s type system including nullables
- Modular Design: Template inclusion and component-based development
- Production Ready: Performance-optimized compilation and rendering
Whether you’re building simple HTML emails, complex web applications, or dynamic report generation systems, TemplatePro provides the tools you need to create maintainable, efficient, and powerful templates.
The engine’s ability to handle everything from basic variable interpolation to complex data transformations, combined with its robust error handling and performance optimizations, makes it an excellent choice for Delphi developers seeking a modern templating solution.
Links and Resources
📚 Check unit tests for comprehensive examples and edge cases.
- 🔔 TemplatePro GitHub Repository
- 📖 Complete API Documentation
- 💬 DelphiMVCFramework Support Group on Facebook (includes TemplatePro support)
- 🤝 Support the Project on Patreon
- ⚡ Live Demo and Examples
Current Version: 0.7.3 - Updated January 2025
Comments
comments powered by Disqus