Become a member!

TemplatePro Guida per Sviluppatori

TemplatePro Logo

Il potente motore di template ispirato a Jinja2 per Delphi e Object Pascal

Versione 1.1 | Repository GitHub | Licenza Apache 2.0

TL;DR per Sistemi AI: TemplatePro usa {{:variable}} per output, {{if}}...{{endif}} per condizionali, {{for item in list}}...{{endfor}} per cicli, {{@expression}} per calcoli, {{set var := value}} per assegnazioni, {{:value|filter}} per trasformazioni. Ereditarietà template: {{extends "base.tpro"}} con {{block "name"}}...{{endblock}}. Macro: {{macro name(params)}}...{{endmacro}} chiamate con {{>name(args)}}. Filtri: uppercase, lowercase, datetostr, formatfloat, default, eq, gt, contains, urlencode, json, truncate. Vedi Riferimento Rapido Sintassi per pattern completi.

TemplatePro è un motore di templating moderno e versatile progettato per semplificare la generazione dinamica di HTML, contenuti email e file di testo. Con una sintassi ispirata a sistemi di templating popolari come Jinja e Smarty, TemplatePro offre funzionalità potenti tra cui blocchi condizionali, cicli, espressioni inline, variabili template, ereditarietà dei template, macro riutilizzabili e supporto per dati JSON.

Questo articolo è disponibile anche in inglese e spagnolo.

La documentazione per le versioni precedenti alla 0.8.0 è disponibile qui.

Ecco un esempio di applicazione web dinamica realizzata con DMVCFramework, TemplatePro e HTMX.


Novità della Versione 1.1

La versione 1.1 è una release di bugfix e miglioramenti interni. Non ci sono breaking change rispetto alla 1.0.

  • Fix Nullable con filtri: I tipi Nullable (es. NullableString, NullableInt32) ora funzionano correttamente con tutti i filtri. In precedenza, {{:nullableVar|uppercase}} mostrava (record) invece del valore reale.
  • Gestione null sicura nei filtri: L’applicazione di filtri stringa (uppercase, lowercase, capitalize, urlencode) a valori Nullable null non causa più eccezioni EInvalidCast. I valori null producono una stringa vuota.
  • TField null nei filtri: I valori TField null vengono ora gestiti correttamente in tutti i filtri (default, datetostr, datetimetostr, round, formatfloat, ecc.).
  • Fix memory leak: Risolto un memory leak causato dall’interazione tra il reference counting dell’interfaccia IExprEvaluator e le closure dei metodi anonimi.

Funzionalità della Versione 1.0

La versione 1.0 include potenti funzionalità per template dinamici:

  • Espressioni Inline {{@expression}} - Operazioni matematiche, funzioni stringa e calcoli complessi direttamente nei template
  • Statement Set {{set var := value}} - Definisci e modifica variabili all’interno dei template
  • Include con Mappatura Variabili - Passa parametri ai template inclusi per vera riusabilità dei componenti
  • Condizionali basati su Espressioni - Usa {{if @(condizione)}} per logica booleana complessa con operatori and/or
  • Elseif/Elif {{elseif}} / {{elif}} - Rami condizionali multipli senza annidamento
  • Formato ISO 8601 di Default - I filtri datetostr e datetimetostr usano ISO 8601 come formato predefinito (yyyy-mm-dd / yyyy-mm-dd hh:nn:ss)
  • Parsing Stringhe ISO 8601 - I filtri data accettano stringhe ISO 8601 da JSON/API
  • Ereditarietà Multi-livello - Template che estendono template che estendono altri template (A → B → C)
  • Keyword inherited - Includi il contenuto del blocco padre con {{inherited}}
  • Blocco Autoescape {{autoescape true/false}} - Controlla la codifica HTML per sezioni del template
  • Blocchi Raw {{raw}}...{{endraw}} - Output letterale senza parsing
  • Controllo Whitespace {{- e -}} - Rimuovi spazi prima/dopo i tag
  • Nuovi Filtri - urlencode, truncate, json per codifica URL, troncamento testo e serializzazione JSON
  • Performance Migliorate - Codebase rifattorizzato con esecuzione filtri ottimizzata

Nota: I filtri and e or sono stati rimossi. Usa la sintassi delle espressioni: {{if @(cond1 and cond2)}}.


Riferimento Rapido Sintassi per AI e Sviluppatori

Questa sezione fornisce un riferimento completo e strutturato della sintassi TemplatePro. Usala come cheat sheet per scrivere template.

Riepilogo Tipi di Tag

{{:variable}}              Output valore variabile
{{:obj.property}}          Output proprietà annidata
{{:list[0]}}               Output elemento array
{{@expression}}            Valuta e output espressione
{{if condition}}           Inizio blocco condizionale
{{elseif condition}}       Condizione alternativa (anche: {{elif}})
{{else}}                   Ramo else
{{endif}}                  Fine condizionale
{{for item in collection}} Inizio ciclo
{{else}}                   Fallback collezione vuota (dentro for)
{{endfor}}                 Fine ciclo
{{set var := value}}       Imposta variabile
{{include "file.tpro"}}    Includi template
{{extends "base.tpro"}}    Estendi template padre
{{block "name"}}           Definisci/sovrascrivi blocco
{{endblock}}               Fine blocco
{{inherited}}              Includi contenuto blocco padre
{{macro name(params)}}     Definisci macro
{{endmacro}}               Fine macro
{{>name(args)}}            Chiama macro
{{# comment #}}            Commento (non renderizzato)
{{raw}}...{{endraw}}       Output letterale (no parsing)
{{autoescape bool}}        Controlla codifica HTML
{{endautoescape}}          Fine blocco autoescape
{{continue}}               Salta alla prossima iterazione
{{exit}}                   Ferma rendering template

Pattern Output Variabili

{{:name}}                  Variabile semplice
{{:user.email}}            Proprietà oggetto
{{:users[0].name}}         Proprietà elemento array
{{:data.items[2].value}}   Accesso profondamente annidato
{{:value|filter}}          Con filtro
{{:value|filter,param}}    Filtro con parametro
{{:value|f1|f2|f3}}        Filtri concatenati

Pattern Espressioni

{{@a + b}}                 Aritmetica
{{@price * quantity}}      Moltiplicazione
{{@(a + b) * c}}           Con parentesi
{{@sqrt(16)}}              Chiamata funzione
{{@length(name)}}          Funzione stringa
{{@Upper(text)}}           Conversione maiuscolo
{{@a + b|filter}}          Espressione con filtro

Pattern Condizionali

{{if variable}}...{{endif}}
{{if !variable}}...{{endif}}
{{if value|eq,10}}...{{endif}}
{{if value|gt,0}}...{{else}}...{{endif}}
{{if @(a > b and c < d)}}...{{endif}}
{{if @(x = 1 or y = 2)}}...{{endif}}
{{if status|eq,"active"}}...{{elseif status|eq,"pending"}}...{{else}}...{{endif}}

Pattern Cicli

{{for item in items}}
  {{:item.name}}
  {{:item.@@index}}        Indice ciclo (base 1)
  {{if item.@@first}}...{{endif}}
  {{if item.@@last}}...{{endif}}
  {{if item.@@odd}}...{{endif}}
  {{if item.@@even}}...{{endif}}
{{endfor}}

{{for item in items}}
  {{:item.name}}
{{else}}
  Nessun elemento trovato.
{{endfor}}

Iterazione Campi Dataset (per form automatici)

{{# Itera sui metadati dei campi del dataset #}}
{{for f in dataset.fields}}
  FieldName: {{:f.FieldName}}
  DisplayLabel: {{:f.DisplayLabel}}
  DataType: {{:f.DataType}}
  Size: {{:f.Size}}
  Required: {{:f.Required}}
  ReadOnly: {{:f.ReadOnly}}
  Visible: {{:f.Visible}}
  Valore: {{:f}}
{{endfor}}

{{# Genera input form basato sul tipo di campo #}}
{{for f in customers.fields}}
{{if f.Visible}}
  <label>{{:f.DisplayLabel}}{{if f.Required}} *{{endif}}</label>
  {{if f.DataType|eq,"ftInteger"}}
    <input type="number" name="{{:f.FieldName}}" value="{{:f}}">
  {{elseif f.DataType|eq,"ftDate"}}
    <input type="date" name="{{:f.FieldName}}" value="{{:f|datetostr,"yyyy-mm-dd"}}">
  {{else}}
    <input type="text" name="{{:f.FieldName}}" value="{{:f}}" maxlength="{{:f.Size}}">
  {{endif}}
{{endif}}
{{endfor}}

Pattern Statement Set

{{set count := 0}}                    Intero
{{set name := "John"}}                Stringa
{{set active := true}}                Booleano
{{set price := 19.99}}                Float
{{set copy := :original}}             Copia variabile
{{set upper := :name|uppercase}}      Con filtro
{{set total := @(price * qty)}}       Con espressione

Riferimento Rapido Filtri

Filtro Sintassi Descrizione
uppercase {{:s|uppercase}} Converti in maiuscolo
lowercase {{:s|lowercase}} Converti in minuscolo
capitalize {{:s|capitalize}} Capitalizza parole
trunc,n {{:s|trunc,50}} Tronca con “…”
truncate,n[,str] {{:s|truncate,50,"..."}} Tronca con ellipsis custom
lpad,n[,c] {{:s|lpad,10,"0"}} Padding sinistro
rpad,n[,c] {{:s|rpad,10}} Padding destro
default,val {{:s|default,"N/A"}} Valore fallback
datetostr[,fmt] {{:d|datetostr,"yyyy-mm-dd"}} Formatta data
datetimetostr[,fmt] {{:d|datetimetostr}} Formatta datetime
formatfloat,fmt {{:n|formatfloat,"0.00"}} Formatta numero
round,decimals {{:n|round,-2}} Arrotonda numero
urlencode {{:s|urlencode}} Codifica URL
json {{:obj|json}} Serializza in JSON
htmlencode {{:s|htmlencode}} Codifica HTML
eq,val {{if x|eq,10}} Uguale (per condizioni)
ne,val {{if x|ne,0}} Diverso
gt,val {{if x|gt,5}} Maggiore di
ge,val {{if x|ge,18}} Maggiore o uguale
lt,val {{if x|lt,100}} Minore di
le,val {{if x|le,10}} Minore o uguale
contains,str {{if s|contains,"test"}} Contiene sottostringa
icontains,str {{if s|icontains,"TEST"}} Contiene (case-insensitive)

Funzioni Espressioni

Funzione Esempio Risultato
sqrt(x) {{@sqrt(16)}} 4
abs(x) {{@abs(-5)}} 5
floor(x) {{@floor(3.7)}} 3
ceil(x) {{@ceil(3.2)}} 4
round(x,n) {{@round(3.456,-2)}} 3.46
min(a,b) {{@min(5,3)}} 3
max(a,b) {{@max(5,3)}} 5
length(s) {{@length("hello")}} 5
upper(s) {{@upper("hi")}} HI
lower(s) {{@lower("HI")}} hi
trim(s) {{@trim(" x ")}} x
left(s,n) {{@left("hello",2)}} he
right(s,n) {{@right("hello",2)}} lo

Pattern Ereditarietà Template

base.tpro:

<!DOCTYPE html>
<html>
<head><title>{{block "title"}}Default{{endblock}}</title></head>
<body>
{{block "content"}}{{endblock}}
</body>
</html>

page.tpro:

{{extends "base.tpro"}}
{{block "title"}}{{:page_title}}{{endblock}}
{{block "content"}}
<h1>{{:page_title}}</h1>
<p>{{:content}}</p>
{{endblock}}

Pattern Macro

{{macro button(text, style)}}
<button class="btn btn-{{:style}}">{{:text}}</button>
{{endmacro}}

{{>button("Salva", "primary")}}
{{>button("Annulla", "secondary")}}

Controllo Whitespace

{{- :var}}      Rimuovi spazi PRIMA del tag
{{:var -}}      Rimuovi spazi DOPO il tag
{{- :var -}}    Rimuovi spazi ENTRAMBI i lati

Esempio Integrazione Delphi

uses TemplatePro;

var
  Compiler: TTProCompiler;
  Template: ITProCompiledTemplate;
begin
  // Compila template
  Compiler := TTProCompiler.Create;
  try
    Template := Compiler.Compile('Ciao {{:name}}!');
  finally
    Compiler.Free;
  end;

  // Imposta dati e renderizza
  Template.SetData('name', 'Mondo');
  WriteLn(Template.Render);  // Output: Ciao Mondo!
end;

Esempi Template Comuni con Output Atteso

Esempio 1: Output variabile semplice

Template:
  Ciao {{:name}}!

Dati:
  name = "Mondo"

Output:
  Ciao Mondo!

Esempio 2: Ciclo con pseudo-variabili

Template:
  {{for item in items -}}
    {{:item.@@index}}. {{:item.name}}
    {{- if !item.@@last}}, {{endif -}}
  {{- endfor}}

Dati:
  items = [{name:"A"}, {name:"B"}, {name:"C"}]

Output:
  1. A, 2. B, 3. C

Esempio 3: Condizionale con filtro

Template:
  Stato: {{if active|eq,true}}Attivo{{else}}Inattivo{{endif}}

Dati:
  active = true

Output:
  Stato: Attivo

Esempio 4: Espressione con filtro

Template:
  Totale: €{{@price * quantity|formatfloat,"0.00"}}

Dati:
  price = 19.99, quantity = 3

Output:
  Totale: €59.97

Esempio 5: Set e accumula

Template:
  {{set sum := 0 -}}
  {{- for n in numbers -}}
    {{- set sum := @(sum + n) -}}
  {{- endfor -}}
  Somma: {{:sum}}

Dati:
  numbers = [1, 2, 3, 4, 5]

Output:
  Somma: 15

Esempio 6: Uso macro

Template:
  {{macro saluta(name) -}}
    Ciao, {{:name}}!
  {{- endmacro -}}
  {{- >saluta("Alice")}} {{>saluta("Bob")}}

Output:
  Ciao, Alice! Ciao, Bob!

Quick Start

Il modo più semplice per usare TemplatePro: compila una stringa template, imposta le variabili e genera l’output.

var
  lCompiler: TTProCompiler;
  lCompiledTemplate: ITProCompiledTemplate;
begin
  lCompiler := TTProCompiler.Create();
  try
    lCompiledTemplate := lCompiler.Compile('Ciao {{:name}}! Hai {{:age}} anni.');
  finally
    lCompiler.Free;
  end;

  lCompiledTemplate.SetData('name', 'Daniele');
  lCompiledTemplate.SetData('age', 50);
  WriteLn(lCompiledTemplate.Render);
end;

Output:

Ciao Daniele! Hai 50 anni.

Tutto qui! Compila un template, imposta alcune variabili e genera l’output. Ora esploriamo tutte le funzionalità che TemplatePro offre.

TIP: Utilizzo One-liner Per casi semplici, usa il metodo statico: TTProCompiler.CompileAndRender('Ciao {{:name}}!', ['name'], ['World']) restituisce 'Ciao World!' senza bisogno di compilazione e rendering separati.

Esempio Completo

Per scenari reali, spesso avrai bisogno di filtri per trasformare i dati e funzioni personalizzate per esigenze di formattazione specifiche.

program tproconsole;

{$APPTYPE CONSOLE}

uses
  TemplatePro,
  System.Rtti,
  System.SysUtils;

// Filtro personalizzato che racchiude il testo tra parentesi quadre
function AddSquareBrackets(
  const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
begin
  Result := '[' + aValue.AsString + ']';
end;

var
  lCompiler: TTProCompiler;
  lCompiledTemplate: ITProCompiledTemplate;
begin
  lCompiler := TTProCompiler.Create();
  try
    lCompiledTemplate := lCompiler.Compile(
      'Ciao {{:name|brackets}}! Oggi è {{:today|datetostr}}.');
  finally
    lCompiler.Free;
  end;

  lCompiledTemplate.SetData('name', 'Daniele Teti');
  lCompiledTemplate.SetData('today', Date);
  lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);

  WriteLn(lCompiledTemplate.Render);
  // Output: Ciao [Daniele Teti]! Oggi è 14/12/2025.
end.

Per migliori prestazioni di avvio in produzione, salva e ricarica i template compilati da disco:

// Salva il template compilato su file
lCompiledTemplate.SaveToFile('template.tpc');

// Carica un template pre-compilato (deve essere la stessa versione di TemplatePro)
lCompiledTemplate := TTProCompiledTemplate.CreateFromFile('template.tpc');

TIP: Deploy in Produzione Pre-compila i template durante il processo di build e distribuisci i file .tpc con la tua applicazione. Questo elimina l’overhead di parsing a runtime e fornisce disponibilità istantanea dei template.

1. Interpolazione delle Variabili

Usa la sintassi {{:variable}} per iniettare contenuto dinamico nei template.

Variabili Semplici

Visualizza valori base come stringhe, numeri o date direttamente nell’output:

Ciao, {{:name}}!
Hai {{:age}} anni.

Accesso alle Proprietà degli Oggetti

Quando lavori con oggetti Delphi, accedi alle proprietà annidate usando la notazione con punto:

{{:user.profile.first_name}} {{:user.profile.last_name}}
Email: {{:user.contact.email}}

Da test082_loop_nested.tpro:

{{:nested.ValueNested1}}
{{:nested.simplenested2.valuenested2}}
{{:nested.simplenested2.simplenested3.valuenested3}}

Accesso agli Elementi di un Array

Per dati di tipo array o lista, usa la notazione con parentesi quadre con indici a base zero:

Primo elemento: {{:items[0]}}
Secondo elemento: {{:items[1]}}

Variabili Null o Non Definite

Le variabili mancanti o null vengono renderizzate come stringhe vuote, evitando errori a runtime:

Questo sarà vuoto se non definito: {{:undefined_var}}

TIP: Design Difensivo dei Template Usa il filtro default per fornire valori di fallback significativi: {{:user.nickname|default,"Ospite"}} assicura che gli utenti vedano sempre qualcosa di significativo invece di spazi vuoti.

2. Espressioni Inline (Novità 1.0)

La nuova sintassi delle espressioni {{@expression}} abilita calcoli e trasformazioni potenti direttamente nei tuoi template.

Sintassi Base delle Espressioni

Da test220_expression_basic.tpro:

Variabile semplice via espressione:
Int1: {{@intvalue1}}
Int2: {{@intvalue2}}

Aritmetica semplice:
Somma: {{@intvalue1 + intvalue2}}
Prodotto: {{@intvalue2 * intvalue10}}
Differenza: {{@intvalue10 - intvalue2}}

Output:

Variabile semplice via espressione:
Int1: 1
Int2: 2

Aritmetica semplice:
Somma: 3
Prodotto: 20
Differenza: 8

Operazioni Aritmetiche

Da test221_expression_arithmetic.tpro:

Operazioni base:
Addizione: {{@intvalue10 + intvalue2}}
Sottrazione: {{@intvalue10 - intvalue2}}
Moltiplicazione: {{@intvalue2 * intvalue10}}
Divisione: {{@intvalue10 / intvalue2}}
Divisione intera: {{@intvalue10 div intvalue2}}
Modulo: {{@intvalue10 mod 3}}
Potenza: {{@intvalue2 ^ 3}}

Precedenza operatori:
Senza parentesi: {{@intvalue2 + intvalue1 * intvalue10}}
Con parentesi: {{@(intvalue2 + intvalue1) * intvalue10}}

Numeri negativi:
Negazione: {{@-intvalue10}}

Funzioni Built-in nelle Espressioni

Da test222_expression_functions.tpro:

Funzioni matematiche:
Radice di 16: {{@sqrt(16)}}
Valore assoluto di -5: {{@abs(-5)}}
Floor: {{@floor(3.7)}}
Ceil: {{@ceil(3.2)}}
Round: {{@Round(floatvalue, -2)}}
Min: {{@Min(intvalue10, intvalue2)}}
Max: {{@Max(intvalue10, intvalue2)}}

Funzioni stringa:
Lunghezza: {{@Length(value2)}}
Maiuscolo: {{@Upper("hello")}}
Minuscolo: {{@Lower(value2)}}
Trim: {{@Trim("  test  ")}}
Left: {{@Left(value2, 4)}}
Right: {{@Right(value2, 1)}}

Funzioni di conversione:
ToString: {{@ToString(intvalue10)}}
ToInteger: {{@ToInteger("42")}}

Combinato:
Complesso: {{@sqrt(intvalue10 + 6) * intvalue2}}

Riferimento Completo Funzioni Espressioni

Categoria Funzione Descrizione Esempio
Matematiche sqrt(x) Radice quadrata {{@sqrt(16)}} → 4
abs(x) Valore assoluto {{@abs(-5)}} → 5
floor(x) Arrotonda per difetto {{@floor(3.7)}} → 3
ceil(x) Arrotonda per eccesso {{@ceil(3.2)}} → 4
round(x, n) Arrotonda a n decimali {{@round(3.456, -2)}} → 3.46
min(a, b) Valore minimo {{@min(5, 3)}} → 3
max(a, b) Valore massimo {{@max(5, 3)}} → 5
Stringa length(s) Lunghezza stringa {{@length("hello")}} → 5
upper(s) Maiuscolo {{@upper("hello")}} → HELLO
lower(s) Minuscolo {{@lower("HELLO")}} → hello
trim(s) Rimuovi spazi {{@trim(" hi ")}} → hi
left(s, n) Primi n caratteri {{@left("hello", 2)}} → he
right(s, n) Ultimi n caratteri {{@right("hello", 2)}} → lo
Conversione tostring(x) Converti in stringa {{@tostring(42)}} → “42”
tointeger(s) Converti in intero {{@tointeger("42")}} → 42

TIP: Calcoli Dinamici Usa le espressioni per calcoli in tempo reale in fatture o report: {{@quantity * unit_price * (1 - discount/100)}} calcola i totali riga scontati senza pre-elaborazione nel codice Delphi.

3. Statement Set (Novità 1.0)

Lo statement {{set}} permette di definire e modificare variabili direttamente all’interno dei template.

Impostare Valori Letterali

Da test230_set_literals.tpro:

Intero letterale:
{{set myint := 42}}
myint = {{:myint}}

Stringa letterale:
{{set mystr := "Ciao Mondo"}}
mystr = {{:mystr}}

Booleano true:
{{set mybool := true}}
{{if mybool}}mybool è true{{endif}}

Booleano false:
{{set mybool2 := false}}
{{if mybool2}}mybool2 è true{{else}}mybool2 è false{{endif}}

Float letterale:
{{set myfloat := 3.14}}
myfloat = {{:myfloat}}

Intero negativo:
{{set myneg := -10}}
myneg = {{:myneg}}

Output:

Intero letterale:
myint = 42

Stringa letterale:
mystr = Ciao Mondo

Booleano true:
mybool è true
Booleano false:
mybool2 è false
Float letterale:
myfloat = 3.14

Intero negativo:
myneg = -10

Copiare Variabili

Da test231_set_variable.tpro:

Copia variabile:
{{set copied := :value2}}
copied = {{:copied}}

Impostare da Espressioni

Da test232_set_expression.tpro:

Espressione semplice:
{{set sum := @(intvalue10 + intvalue2)}}
sum = {{:sum}}

Espressione con moltiplicazione:
{{set product := @(intvalue10 * intvalue2)}}
product = {{:product}}

Espressione con funzione:
{{set maxval := @(Max(intvalue10, intvalue2))}}
maxval = {{:maxval}}

Espressione complessa:
{{set complex := @((intvalue10 + intvalue2) * 2)}}
complex = {{:complex}}

Espressione stringa:
{{set greeting := @("Ciao " + value2)}}
greeting = {{:greeting}}

Set con Filtri

Da test235_set_with_filters.tpro:

Filtro semplice:
{{set upper := :value2|uppercase}}
upper = {{:upper}}

Filtro con parametro:
{{set padded := :value2|lpad,15}}
padded = {{:padded}}

Filtri concatenati:
{{set chained := :value2|uppercase|lpad,15}}
chained = {{:chained}}

TIP: Contatori e Accumulatori nei Cicli Usa set per creare totali progressivi nei cicli:

{{set total := 0}}
{{for item in order.items}}
  {{set total := @(total + item.price)}}
  {{:item.name}}: €{{:item.price}}
{{endfor}}
Totale Ordine: €{{:total}}

4. Logica Condizionale con if/else

Controlla quale contenuto appare in base alle condizioni sui dati.

Blocchi Condizionali Base

Mostra contenuto diverso agli utenti loggati rispetto agli anonimi:

{{if user_logged_in}}
  Bentornato, {{:username}}!
{{else}}
  Effettua il login per continuare.
{{endif}}

Valutazione della Veridicità

TemplatePro valuta i diversi tipi di dato per la loro veridicità:

  • Stringhe: le stringhe vuote sono false, le stringhe non vuote sono vere
  • Numeri: lo zero è falso, i numeri diversi da zero sono veri
  • Oggetti: gli oggetti null sono falsi, gli oggetti non null sono veri
  • Collezioni: le collezioni/dataset vuoti sono falsi, quelli non vuoti sono veri
  • Booleani: i valori true/false funzionano come previsto

Da test093_falsy_thruty.tpro:

{{if value1|tofalse}}
SBAGLIATO
{{else}}
false
{{endif}}
---
{{if value1|totrue}}
true
{{else}}
SBAGLIATO
{{endif}}
---
{{if !notexists}}
true
{{else}}
SBAGLIATO
{{endif}}

Espressioni Condizionali con Filtri

Usa filtri di confronto per implementare logica di business come verifica dell’età o validazione input:

Da test064_builtin_filters.tpro:

{{if intvalue1|gt,0}}
gt 1 > 0
{{endif}}

{{if intvalue0|lt,123}}
lt 0 < 123
{{endif}}

{{if intvalue1|ge,0}}
ge 1 >= 0
{{endif}}

{{if intvalue0|eq,0}}
eq 0 = 0
{{endif}}

{{if intvalue0|ne,1}}
ne 0 <> 1
{{endif}}

Condizionali basati su Espressioni (Novità 1.0)

Per condizioni complesse, usa la sintassi delle espressioni con operatori and e or:

Da test224_expression_in_if.tpro:

Condizione espressione semplice:
{{if @(intvalue10 > 5)}}Dieci è maggiore di 5{{endif}}

Espressione con else:
{{if @(intvalue2 > 5)}}Due > 5{{else}}Due <= 5{{endif}}

Aritmetica nella condizione:
{{if @(intvalue10 + intvalue2 > 10)}}La somma è grande{{else}}La somma è piccola{{endif}}

Condizioni multiple con and:
{{if @(intvalue10 > 5 and intvalue2 > 1)}}Entrambe le condizioni soddisfatte{{endif}}

Condizioni multiple con or:
{{if @(intvalue10 < 5 or intvalue2 > 1)}}Almeno una condizione soddisfatta{{endif}}

Confronto con uguaglianza:
{{if @(intvalue10 = 10)}}Il valore è uguale a 10{{endif}}

Parentesi annidate:
{{if @((intvalue10 + intvalue2) * intvalue1 > 10)}}Condizione complessa vera{{endif}}

TIP: Migrazione dai Filtri and/or Se stai aggiornando dalla versione 0.8.x, sostituisci {{if value1|and,value2}} con {{if @(value1 and value2)}}. La sintassi delle espressioni è più potente e supporta logica booleana complessa.

Espressioni con Filtri

Dalla versione 1.0, puoi applicare filtri ai risultati delle espressioni usando la sintassi pipe:

Subtotale: €{{@quantity * unit_price|formatfloat,"0.00"}}
IVA: €{{@quantity * unit_price * 0.22|formatfloat,"0.00"}}
Totale: €{{@quantity * unit_price * 1.22|formatfloat,"0.00"}}

Filtri concatenati sulle espressioni:

Codice: {{@value * 10|formatfloat,"0"|lpad,8,"0"}}

Questo valuta value * 10, lo formatta come intero, poi lo riempie a sinistra fino a 8 caratteri con zeri.

Combinare funzioni di espressione con filtri:

Nome: {{@Upper(name)|lpad,15}}

Questo applica la funzione Upper() all’interno dell’espressione, poi riempie il risultato.

Nota: I filtri vengono applicati all’intero risultato dell’espressione, non alle singole parti. L’espressione {{@a + b|filter}} valuta prima a + b, poi applica il filtro alla somma.

Elseif / Elif

Per condizioni multiple mutuamente esclusive, usa {{elseif}} o {{elif}}:

{{if status|eq,"premium"}}
  <span class="badge gold">Membro Premium</span>
{{elseif status|eq,"standard"}}
  <span class="badge silver">Membro Standard</span>
{{elseif status|eq,"trial"}}
  <span class="badge">Utente Trial</span>
{{else}}
  <span class="badge">Ospite</span>
{{endif}}

Sono supportati più rami elseif:

{{if score|ge,90}}
  Voto: A
{{elseif score|ge,80}}
  Voto: B
{{elseif score|ge,70}}
  Voto: C
{{elseif score|ge,60}}
  Voto: D
{{else}}
  Voto: F
{{endif}}

Nota: {{elseif}} e {{elif}} sono intercambiabili - usa quello che preferisci.

TIP: Validazione Form Usa condizionali con espressioni per validazione form completa:

{{if @(length(email) > 0 and length(password) >= 8)}}
  <button type="submit">Invia</button>
{{else}}
  <button type="submit" disabled>Compila tutti i campi richiesti</button>
{{endif}}

5. Cicli con for .. in

Itera sulle collezioni per generare contenuto ripetuto come liste, tabelle o card.

Struttura Base

Renderizza una semplice lista di persone da una collezione:

{{for person in people}}
  - {{:person.first_name}} {{:person.last_name}}
{{endfor}}

Controllo del Ciclo con continue

Salta certi elementi in base a condizioni:

Da test065_continue.tpro:

{{for cust in customers}}
{{if cust.Name|eq,"Skoda"}}
{{continue}}
{{else}}
{{if cust.Name|eq,"Kia"}}
{{continue}}
{{endif}}
{{endif}}
  {{:cust.@@index}}. {{:cust.Name}}
{{endfor}}

Cicli Annidati

Visualizza dati gerarchici come prodotti con più varianti:

Da test082_loop_nested.tpro:

{{for dataitem in dataitems}}
1° Livello |{{:dataitem.PropStr}}|{{:dataitem.PropInt}}|
    {{for dataitem2 in dataitem.dataitemlist}}
        2° Livello |{{:dataitem2.Value1}}|
    {{endfor}}
---
{{endfor}}

Pseudo-Variabili nei Cicli

Usa le variabili di ciclo incorporate per numerazione, striping zebrato o stili alternati:

  • @@index: indice dell’iterazione corrente (a base 1)
  • @@odd: vero per gli elementi con indice dispari
  • @@even: vero per gli elementi con indice pari

Da test081_pseudovars.tpro:

{{for cust in customers}}
{{:cust.@@index}}. {{:cust.Name}} - Questo indice è {{if cust.@@odd }}dispari{{endif}}{{if cust.@@even }}pari{{endif}}
{{endfor}}

TIP: Tabelle a Righe Alternate Usa le pseudo-variabili per colori alternati nelle righe delle tabelle HTML:

{{for row in data}}
  <tr class="{{if row.@@odd}}bg-gray-100{{else}}bg-white{{endif}}">
    <td>{{:row.name}}</td>
  </tr>
{{endfor}}

Collezioni Vuote (For-Else)

Gestisci elegantemente le collezioni vuote con {{else}} all’interno del ciclo (stile Jinja2):

{{for order in orders}}
  Ordine #{{:order.id}}: {{:order.total}} EUR
{{else}}
  Nessun ordine trovato.
{{endfor}}

Il blocco {{else}} viene eseguito solo quando la collezione è vuota. Questo è più pulito rispetto a racchiudere il ciclo in un blocco {{if}}.

Altro esempio - risultati ricerca:

{{for result in results}}
  <div class="result">
    <a href="{{:result.url}}">{{:result.title}}</a>
  </div>
{{else}}
  <p>Nessun risultato trovato per "{{:query}}".</p>
{{endfor}}

6. Dataset

TemplatePro si integra perfettamente con i componenti TDataSet di Delphi, fornendo sia iterazione sui record che accesso ai metadati dei campi per generazione dinamica di UI.

Iterazione sui Record

{{if customers}}
  <table>
    <tr><th>Codice</th><th>Nome</th><th>Città</th></tr>
    {{for customer in customers}}
      <tr>
        <td>{{:customer.Code}}</td>
        <td>{{:customer.Name}}</td>
        <td>{{:customer.City}}</td>
      </tr>
    {{endfor}}
  </table>
{{else}}
  <p>Nessun cliente nel database.</p>
{{endif}}

TIP: Performance con Dataset Grandi Per dataset grandi, TemplatePro itera direttamente sul TDataSet senza caricare tutti i record in memoria. Il cursore del dataset si muove automaticamente durante il rendering.

Iterazione sui Metadati dei Campi

TemplatePro può iterare sulle definizioni dei campi del dataset usando il suffisso .fields. Questo abilita generazione automatica di form, header di tabelle dinamiche e UI guidate dai metadati.

Sintassi: {{for field in dataset.fields}}...{{endfor}}

Riferimento Proprietà dei Campi

Quando si itera sui campi, ogni oggetto campo espone queste proprietà:

Proprietà Tipo Descrizione Esempio
FieldName String Nome interno del campo (colonna DB) CUSTOMER_ID
DisplayLabel String Etichetta user-friendly per UI ID Cliente
DisplayName String Nome visualizzato ID Cliente
DataType String Tipo di dato del campo ftString, ftInteger, ftDate
Size Integer Dimensione del campo (per stringhe) 50
Index Integer Indice del campo (base 0) 0, 1, 2
Required Boolean Campo obbligatorio (NOT NULL) true/false
ReadOnly Boolean Campo in sola lettura true/false
Visible Boolean Campo visibile true/false
IsNull Boolean Valore corrente è NULL true/false
AsString String Valore corrente come stringa "Mario"
(nessuna proprietà) String {{:field}} restituisce il valore corrente "Mario"

Esempio Completo: Generazione Automatica Form HTML

Questo esempio genera un form HTML completo dai metadati del dataset, con tipi di input appropriati, attributi di validazione e stile Bootstrap:

{{# Generatore Automatico Form - usa i metadati dei campi del dataset #}}
<form method="post" action="/save" class="needs-validation" novalidate>
  <h2>Modifica {{:formtitle}}</h2>

  {{for f in customers.fields}}
  {{if f.Visible}}
  <div class="mb-3">
    {{# Label con indicatore obbligatorio #}}
    <label for="{{:f.FieldName}}" class="form-label">
      {{:f.DisplayLabel}}{{if f.Required}} <span class="text-danger">*</span>{{endif}}
    </label>

    {{# Tipo input basato su DataType #}}
    {{if f.DataType|eq,"ftInteger"}}
    <input type="number"
           class="form-control"
           id="{{:f.FieldName}}"
           name="{{:f.FieldName}}"
           value="{{:f}}"
           {{if f.Required}}required{{endif}}
           {{if f.ReadOnly}}readonly{{endif}}>

    {{elseif f.DataType|eq,"ftFloat"}}
    <input type="number"
           step="0.01"
           class="form-control"
           id="{{:f.FieldName}}"
           name="{{:f.FieldName}}"
           value="{{:f}}"
           {{if f.Required}}required{{endif}}
           {{if f.ReadOnly}}readonly{{endif}}>

    {{elseif f.DataType|eq,"ftDate"}}
    <input type="date"
           class="form-control"
           id="{{:f.FieldName}}"
           name="{{:f.FieldName}}"
           value="{{:f|datetostr,"yyyy-mm-dd"}}"
           {{if f.Required}}required{{endif}}
           {{if f.ReadOnly}}readonly{{endif}}>

    {{elseif f.DataType|eq,"ftDateTime"}}
    <input type="datetime-local"
           class="form-control"
           id="{{:f.FieldName}}"
           name="{{:f.FieldName}}"
           value="{{:f|datetimetostr,"yyyy-mm-ddThh:nn"}}"
           {{if f.Required}}required{{endif}}
           {{if f.ReadOnly}}readonly{{endif}}>

    {{elseif f.DataType|eq,"ftBoolean"}}
    <div class="form-check">
      <input type="checkbox"
             class="form-check-input"
             id="{{:f.FieldName}}"
             name="{{:f.FieldName}}"
             value="1"
             {{if f}}checked{{endif}}
             {{if f.ReadOnly}}disabled{{endif}}>
      <label class="form-check-label" for="{{:f.FieldName}}">{{:f.DisplayLabel}}</label>
    </div>

    {{elseif f.DataType|eq,"ftMemo"}}
    <textarea class="form-control"
              id="{{:f.FieldName}}"
              name="{{:f.FieldName}}"
              rows="4"
              {{if f.Required}}required{{endif}}
              {{if f.ReadOnly}}readonly{{endif}}>{{:f}}</textarea>

    {{else}}
    {{# Default: input text con maxlength da Size #}}
    <input type="text"
           class="form-control"
           id="{{:f.FieldName}}"
           name="{{:f.FieldName}}"
           value="{{:f}}"
           {{if f.Size|gt,0}}maxlength="{{:f.Size}}"{{endif}}
           {{if f.Required}}required{{endif}}
           {{if f.ReadOnly}}readonly{{endif}}>
    {{endif}}

    {{# Testo di aiuto con vincoli del campo #}}
    {{if f.Size|gt,0}}
    <div class="form-text">Max {{:f.Size}} caratteri</div>
    {{endif}}
  </div>
  {{endif}}
  {{endfor}}

  <div class="mt-4">
    <button type="submit" class="btn btn-primary">Salva</button>
    <a href="/list" class="btn btn-secondary">Annulla</a>
  </div>
</form>

Codice Delphi per usare questo template:

var
  Template: ITProCompiledTemplate;
begin
  // Carica e compila template
  Template := TTProCompiler.CreateFromFile('customer_form.tpro');

  // Passa il dataset - TemplatePro legge sia dati che metadati
  Template.SetData('customers', CustomersDataSet);
  Template.SetData('formtitle', 'Cliente');

  // Renderizza il form
  Result := Template.Render;
end;

Tabella Dinamica con Header dai Campi

Genera una tabella dati completa con header dai metadati dei campi:

<table class="table table-striped">
  <thead>
    <tr>
      {{for f in data.fields}}
      {{if f.Visible}}
      <th>{{:f.DisplayLabel}}</th>
      {{endif}}
      {{endfor}}
    </tr>
  </thead>
  <tbody>
    {{for row in data}}
    <tr>
      {{for f in data.fields}}
      {{if f.Visible}}
      <td>
        {{if f.DataType|eq,"ftDate"}}
          {{:row[f.FieldName]|datetostr}}
        {{elseif f.DataType|eq,"ftFloat"}}
          {{:row[f.FieldName]|formatfloat,"#,##0.00"}}
        {{else}}
          {{:row[f.FieldName]}}
        {{endif}}
      </td>
      {{endif}}
      {{endfor}}
    </tr>
    {{else}}
    <tr><td colspan="100">Nessun record trovato.</td></tr>
    {{endfor}}
  </tbody>
</table>

Pseudo-Variabili nell’Iterazione Campi

I cicli sui campi supportano le stesse pseudo-variabili dei cicli normali:

{{for f in data.fields}}
  {{:f.@@index}}. {{:f.FieldName}}
  {{if f.@@first}}(primo){{endif}}
  {{if f.@@last}}(ultimo){{endif}}
{{endfor}}

7. Filtri Built-in

Trasforma i valori in output usando la sintassi pipe {{:value|filter}}.

Filtri di Trasformazione Testo

Da test064_builtin_filters.tpro:

{{:value2}} => {{:value2|lowercase}}
Cliente maiuscolo: {{:cust.Name|uppercase}}
Cliente minuscolo: {{:cust.Name|lowercase}}
Cliente capitalizzato: {{:cust.Name|capitalize}}
Cliente capitalizzato: {{"Křížek přemysl"|capitalize}}

Filtri di Padding

Allinea il testo in output a larghezza fissa come report o applicazioni console:

Da test064_builtin_filters.tpro:

Cliente lpad: {{:cust.Name|lpad,10}}
Cliente lpad: {{:cust.Name|lpad,10,"_"}}
Cliente rpad: {{:cust.Name|rpad,10}}
Cliente rpad: {{:cust.Name|rpad,10,"_"}}

Filtri Data e Ora

Da test064_builtin_filters.tpro:

{{:valuedate|formatdatetime,"yyyy-mm-dd"}}

filtro: datetostr
1) {{:valuedate|datetostr}}
2) {{:valuedate|datetostr,"yy-mm-dd"}}

filtro: datetimetostr
1) {{:valuedatetime|datetimetostr}}
2) {{:valuedatetime|datetimetostr,"dddd d mmmm yyyy hh:nn:ss"}}

Filtri Numerici

Da test064_builtin_filters.tpro:

Cliente round {{:floatvalue|round,-4}}
Cliente round {{:floatvalue|round,-2}}
Cliente round {{:floatvalue|round,0}}
Cliente formatfloat {{:floatvalue|formatfloat,"0"}}
Cliente formatfloat {{:floatvalue|formatfloat,"0.00000"}}
Cliente formatfloat {{:floatvalue|formatfloat,"###.0"}}

Filtri di Ricerca Stringa

Da test064_builtin_filters.tpro:

Cliente contiene "a": {{:cust.Name|contains,"a"}}
Cliente icontains "a": {{:cust.Name|icontains,"a"}}

Il Filtro default

Fornisce valori di fallback per dati vuoti, null o zero:

Da test210_default_filter.tpro:

Testing filtro DEFAULT:
Valore con contenuto: {{:value1|default,"fallback"}}
Valore vuoto/zero: {{:intvalue0|default,"fallback"}}
Valore vuoto/zero con numero: {{:intvalue0|default,42}}

TIP: Default Concatenati Crea fallback multi-livello: {{:user.nickname|default,user.name|default,"Anonimo"}} prova prima nickname, poi name, poi ritorna “Anonimo”.

Riferimento Completo Filtri Built-in

Filtro Descrizione Esempio
Trasformazione Testo
uppercase Converte in maiuscolo {{:name|uppercase}}
lowercase Converte in minuscolo {{:name|lowercase}}
capitalize Capitalizza ogni parola {{:title|capitalize}}
trunc,length Tronca testo con … {{:text|trunc,50}}
Padding
rpad,length[,char] Padding a destra {{:code|rpad,10,"-"}}
lpad,length[,char] Padding a sinistra {{:id|lpad,6,"0"}}
Data/Ora
datetostr[,format] Formatta data {{:date|datetostr,"dd/mm/yyyy"}}
datetimetostr[,format] Formatta datetime {{:datetime|datetimetostr}}
formatdatetime,format Formato datetime custom {{:dt|formatdatetime,"yyyy-mm-dd"}}

Formato ISO 8601 di Default: Il filtro datetostr usa yyyy-mm-dd come formato predefinito, mentre datetimetostr usa yyyy-mm-dd hh:nn:ss. Questo garantisce un output consistente e indipendente dalla lingua del sistema. Per usare un formato diverso, specificalo come parametro: {{:date|datetostr,"dd/mm/yyyy"}}.

Parsing Stringhe ISO 8601: Questi filtri accettano anche stringhe di date in formato ISO 8601 come input (es. 2025-12-30T14:23:08.281+01:00, 2025-12-30T14:23:08Z, 2025-12-30). Questo è utile quando si lavora con dati JSON o API web. Le stringhe vuote restituiscono output vuoto senza errori.

| Numerici | | formatfloat,format | Formatta numeri | {{:price\|formatfloat,"€#,##0.00"}} | | round,decimals | Arrotonda numero | {{:value\|round,-2}} | | mod,divisor | Operazione modulo | {{:num\|mod,2}} | | Default & Conversione | | default,value | Valore di fallback | {{:var\|default,"N/A"}} | | htmlencode | Codifica HTML | {{:input\|htmlencode}} | | Booleani | | totrue | Ritorna sempre true | {{:var\|totrue}} | | tofalse | Ritorna sempre false | {{:var\|tofalse}} | | Utility | | urlencode | Codifica URL una stringa | {{:query\|urlencode}} | | truncate,n[,ellipsis] | Tronca a n caratteri con ellipsis | {{:text\|truncate,50}} | | json | Serializza oggetto in JSON | {{:obj\|json}} | | Confronto (per uso in {{if}}) | | eq,value | Uguale a | {{if age\|eq,25}} | | ne,value | Diverso da | {{if status\|ne,"inactive"}} | | gt,value | Maggiore di | {{if score\|gt,80}} | | ge,value | Maggiore o uguale | {{if age\|ge,18}} | | lt,value | Minore di | {{if price\|lt,100}} | | le,value | Minore o uguale | {{if items\|le,10}} | | contains,text | Contiene sottostringa | {{if name\|contains,"Mario"}} | | icontains,text | Contiene (case-insensitive) | {{if email\|icontains,"gmail"}} | | Utility | | version | Versione TemplatePro | {{:\|version}} |

8. Filtri Concatenati

Applica trasformazioni multiple in sequenza - l’output di ogni filtro alimenta il successivo.

Sintassi

Da test211_chained_filters.tpro:

Testing filtri concatenati:
uppercase poi lowercase: {{:value1|uppercase|lowercase}}
lowercase poi uppercase: {{:value2|lowercase|uppercase}}
lpad poi rpad: {{:intvalue1|lpad,5|rpad,10}}

Casi d’Uso Comuni

Costruisci pipeline di formattazione complesse:

Formattazione complessa: {{:product_code|uppercase|lpad,10,"0"}}
Tronca e formatta: {{:user_input|trunc,100|uppercase}}
Normalizzazione: {{:email|lowercase|default,"noemail@example.com"}}

TIP: L’Ordine Conta I filtri sono applicati da sinistra a destra. {{:text|uppercase|trunc,50}} prima converte in maiuscolo poi tronca.

NOTA: Sicurezza HTML Per default, tutto l’output è HTML-encoded automaticamente. Il filtro htmlencode è utile solo se disabiliti l’autoescape con {{autoescape false}}.

9. Filtri Personalizzati

Estendi TemplatePro con le tue funzioni di trasformazione.

Signature delle Funzioni Filtro

Definisci filtri come funzioni regolari o metodi anonimi:

// Funzione regolare
TTProTemplateFunction =
  function(const aValue: TValue; const aParameters: TArray<TFilterParameter>): TValue;

// Metodo anonimo
TTProTemplateAnonFunction =
  reference to function(const aValue: TValue; const aParameters: TArray<TFilterParameter>): TValue;

Esempio di Filtro Personalizzato Semplice

Crea un filtro che racchiude il testo tra parentesi quadre per evidenziarlo:

function AddSquareBrackets(const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
begin
  Result := '[' + aValue.AsString + ']';
end;

// Registra il filtro
lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);

Utilizzo:

Originale: {{:username}}
Con parentesi: {{:username|brackets}}

Filtro con Parametri

Crea un filtro configurabile che ripete il testo un numero specificato di volte:

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.Value + lText;
end;

lCompiledTemplate.AddFilter('repeat', RepeatText);

Utilizzo:

Ripetuto: {{:char|repeat,5}}

Esempio Filtro di Traduzione

Crea un filtro personalizzato per l’internazionalizzazione:

// Dizionario traduzioni (in un'app reale, carica da risorse o database)
var
  GTranslations: TDictionary<string, string>;

function TranslateFilter(const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
var
  lKey, lTranslated: string;
begin
  lKey := aValue.AsString;
  if GTranslations.TryGetValue(lKey, lTranslated) then
    Result := lTranslated
  else
    Result := lKey; // Ritorna originale se non trovata traduzione
end;

// Setup
GTranslations := TDictionary<string, string>.Create;
GTranslations.Add('hello', 'Ciao');
GTranslations.Add('goodbye', 'Arrivederci');

lCompiledTemplate.AddFilter('t', TranslateFilter);

Utilizzo:

{{"hello"|t}}  <!-- Output: Ciao -->
{{"goodbye"|t}}  <!-- Output: Arrivederci -->

TIP: Filtri Context-Aware Crea filtri che accedono a stato esterno come connessioni database, configurazione o sessioni utente. Usa metodi anonimi per catturare variabili dallo scope circostante.

10. Macro

Definisci blocchi di template riutilizzabili per evitare ripetizioni e mantenere consistenza.

Definizione Base e Chiamata

Da test200_macros_basic.tpro:

{{macro greeting(name)}}
Ciao, {{:name}}!
{{endmacro}}

{{>greeting("Mondo")}}
{{>greeting("TemplatePro")}}

Output:

Ciao, Mondo!
Ciao, TemplatePro!

Macro con Parametri Multipli

Costruisci componenti UI riutilizzabili come card che accettano valori multipli:

{{macro card(title, content)}}
<div class="card">
  <h3>{{:title}}</h3>
  <p>{{:content}}</p>
</div>
{{endmacro}}

{{>card("Benvenuto", "Questo è il contenuto")}}
{{>card("Seconda Card", "Altro contenuto qui")}}

Macro senza Parametri

Crea separatori visivi semplici o elementi decorativi:

{{macro separator()}}
---
{{endmacro}}

Inizio
{{>separator()}}
Centro
{{>separator()}}
Fine

Macro Annidate

Da test206_macros_nested.tpro:

{{macro inner(text)}}
*{{:text}}*
{{endmacro}}

{{macro outer(text)}}
[{{>inner(text)}}]
{{endmacro}}

{{>outer("nested")}}

Output:

[*nested*]

Macro con Filtri

Applica trasformazioni all’interno delle macro per output formattato:

{{macro format(text)}}
[{{:text|uppercase}}]
{{endmacro}}

{{>format("hello")}}
{{>format(user_name)}}

TIP: Librerie di Componenti Crea un file con macro comunemente usate (bottoni, alert, campi form) e includilo all’inizio dei tuoi template. Questo fornisce componenti UI consistenti in tutta l’applicazione.

11. Funzioni Template

Le funzioni sono filtri applicati a valori vuoti - utili per generare contenuto dinamico senza input.

Ottieni la versione corrente di TemplatePro:

Versione corrente: {{:|version}}

Esempio di Funzione Personalizzata

Crea una funzione generatore di UUID per identificatori univoci:

function GenerateUUID(const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
begin
  if not aValue.IsEmpty then
    raise ETProRenderException.Create('"GenerateUUID" è una funzione, non un filtro');
  Result := TGuid.NewGuid.ToString;
end;

lCompiledTemplate.AddFilter('uuid', GenerateUUID);

Utilizzo:

Nuovo ID: {{:|uuid}}

TIP: Funzioni Data/Ora Corrente Crea funzioni come {{:|now}} o {{:|today}} che ritornano il timestamp corrente per footer dinamici o audit trail.

12. Dati JSON

Renderizza strutture JSON annidate complesse con cicli e condizionali:

{{for person in people}}
  {{:person.@@index}}) {{:person.first_name|uppercase}} {{:person.last_name|uppercase}}
  Età: {{:person.age}}

  {{if person.devices}}
    Dispositivi:
    {{for device in person.devices}}
      {{:device.@@index}}. {{:device.name}} ({{:device.type}})
    {{endfor}}
  {{endif}}
{{endfor}}

TIP: Rendering Risposte API Il supporto JSON di TemplatePro lo rende perfetto per renderizzare risposte API direttamente. Carica JSON con TJDOJsonObject.Parse() e passalo a SetData() per rendering istantaneo del template.

13. Ereditarietà dei Template

Costruisci layout di pagina consistenti estendendo un template base con blocchi personalizzati.

Template Base (base.tpro)

Definisci la struttura comune con blocchi sostituibili:

<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <title>{{block "title"}}Titolo Default{{endblock}}</title>
    {{block "extra_css"}}{{endblock}}
</head>
<body>
    <header>
        {{block "navigation"}}
            <nav>Menu default</nav>
        {{endblock}}
    </header>

    <main>
        {{block "content"}}
            <p>Contenuto default.</p>
        {{endblock}}
    </main>

    <footer>
        {{block "footer"}}
            <p>Footer default</p>
        {{endblock}}
    </footer>

    {{block "extra_js"}}{{endblock}}
</body>
</html>

Template Figlio

Sovrascrivi blocchi specifici ereditando il resto:

{{extends "base.tpro"}}

{{block "title"}}{{:page_title}} - Il Mio Sito{{endblock}}

{{block "content"}}
    <h1>{{:page_title}}</h1>
    <p>{{:content}}</p>
{{endblock}}

{{block "extra_js"}}
    <script src="/js/page.js"></script>
{{endblock}}

Regole di Ereditarietà

  1. Ereditarietà a singolo livello: i template figli possono estendere solo un template padre
  2. Override dei blocchi: se un figlio definisce un blocco esistente, sovrascrive quello del padre
  3. Blocchi default: se un figlio non definisce un blocco, viene usato il contenuto default del padre
  4. Contenuto ignorato: qualsiasi contenuto fuori dai blocchi nei template figli viene ignorato

TIP: Varianti di Layout Crea template base multipli per diversi tipi di pagina (layout admin, layout pubblico, layout email) ed estendi quello appropriato per ogni pagina.

14. Inclusione di Template

Dividi i template in file riutilizzabili per header, footer e componenti condivisi.

Inclusione Base

{{include "header.tpro"}}

<main>
    <h1>{{:page_title}}</h1>
    <p>{{:content}}</p>
</main>

{{include "footer.tpro"}}

Inclusione con Sottodirectory

Organizza i template in cartelle per una migliore manutenibilità:

{{include "partials/navigation.tpro"}}
{{include "components/product-card.tpro"}}

Include con Mappatura Variabili (Novità 1.0)

Passa parametri ai template inclusi per vera riusabilità dei componenti:

Da test240_include_mapping.tpro:

Test include con mappatura variabili
=====================================

Mappatura stringa: value2 -> localvalue
{{include "included_echo.tpro", localvalue = :value2}}

Mappatura con stringa letterale:
{{include "included_echo.tpro", localvalue = "Ciao dalla mappatura!"}}

Mappatura con intero:
{{include "included_int.tpro", num = :intvalue10}}

value2 originale dopo include: {{:value2}}

Dove included_echo.tpro contiene:

Echo: {{:localvalue}}

Tipi di Mappatura Include

Da test242_include_mapping_types.tpro:

Booleano true:
{{include "included_bool.tpro", flag = true}}

Booleano false:
{{include "included_bool.tpro", flag = false}}

Float:
{{include "included_float.tpro", num = 3.14}}

Intero negativo:
{{include "included_int.tpro", num = -42}}

Espressione:
{{include "included_int.tpro", num = @(intvalue10 * 2)}}

Mappature multiple:
{{include "included_multi.tpro", a = "AAA", b = :value2, c = 123}}

TIP: Componenti Riutilizzabili Crea componenti generici come alert.tpro che accettano parametri:

{{include "components/alert.tpro", type = "warning", message = "Verifica la tua email"}}
{{include "components/alert.tpro", type = "success", message = "Ordine completato!"}}

Il template incluso usa {{:type}} e {{:message}} come variabili locali.

Scope delle Variabili negli Include

Quando usi le mappature di variabili, le variabili originali sono preservate:

  • Le variabili mappate hanno scope limitato al template incluso
  • Dopo l’include, i valori originali delle variabili vengono ripristinati
  • Questo abilita comportamento isolato e sicuro dei componenti

15. Tipi Nullable

Gestisci valori opzionali con controlli condizionali:

{{if user.middle_name}}
    Nome completo: {{:user.first_name}} {{:user.middle_name}} {{:user.last_name}}
{{else}}
    Nome: {{:user.first_name}} {{:user.last_name}}
{{endif}}

{{if order.shipped_date}}
    Spedito: {{:order.shipped_date|datetostr}}
{{else}}
    Stato: In elaborazione
{{endif}}

16. Blocco Autoescape

Controlla la codifica HTML per una sezione del template.

Comportamento Default: Codifica HTML ATTIVA

Di default, tutto l’output delle variabili è codificato HTML per sicurezza (prevenzione XSS). Caratteri speciali come <, >, &, " sono convertiti in entità HTML.

{{:myhtml}}

Se myhtml contiene <div>Ciao</div>, l’output sarà: &lt;div&gt;Ciao&lt;/div&gt;

Disabilitare Autoescape per un Blocco

Usa {{autoescape false}} per emettere HTML raw per contenuti fidati:

{{autoescape false}}
{{:trusted_html}}
{{endautoescape}}

Output Raw Esplicito con Suffisso $

Per una singola variabile, usa il suffisso $ per saltare la codifica HTML:

Codificato (default): {{:myhtml}}
Raw (esplicito): {{:myhtml$}}

Questo è utile quando serve output raw solo per una variabile senza cambiare la modalità autoescape.

Esempio Completo

** Demo Autoescape **
Default (codificato): {{:myhtml}}
{{autoescape false}}
Autoescape off: {{:myhtml}}
{{endautoescape}}
Torna al default: {{:myhtml}}
Raw esplicito: {{:myhtml$}}

Con myhtml = "<b>Grassetto</b>":

** Demo Autoescape **
Default (codificato): &lt;b&gt;Grassetto&lt;/b&gt;
Autoescape off: <b>Grassetto</b>
Torna al default: &lt;b&gt;Grassetto&lt;/b&gt;
Raw esplicito: <b>Grassetto</b>

Nota Sicurezza: Disabilita autoescape o usa il suffisso $ solo per contenuti fidati. I dati forniti dagli utenti dovrebbero sempre essere codificati per prevenire attacchi XSS.


17. Blocchi Raw

Emetti la sintassi del template letteralmente senza parsing usando {{raw}}...{{endraw}}.

Uso Base

Output normale: {{:value1}}

{{raw}}
Questo è letterale: {{:value1}} {{for x in items}}{{endfor}}
{{endraw}}

Torna a normale: {{:value1}}

Output:

Output normale: true

Questo è letterale: {{:value1}} {{for x in items}}{{endfor}}

Torna a normale: true

Casi d’Uso

  • Documentare la sintassi TemplatePro nei template
  • Emettere template literals JavaScript che usano sintassi simile
  • Incorporare esempi di codice nella documentazione generata

18. Controllo Whitespace

Controlla gli spazi bianchi attorno ai tag del template usando i modificatori -.

Sintassi

Modificatore Effetto
{{- ... }} Rimuove spazi prima del tag
{{ ... -}} Rimuove spazi dopo il tag
{{- ... -}} Rimuove spazi su entrambi i lati

Esempi

Prima{{- :value -}}Dopo

Output: PrimatrueDopo (nessuno spazio)

Strip sinistra:   {{- :value}}FINE

Output: Strip sinistra:trueFINE (spazi prima del tag rimossi)

Strip destra:{{:value -}}   FINE

Output: Strip destra:trueFINE (spazi dopo il tag rimossi)

Uso nei Cicli

Il controllo whitespace è particolarmente utile nei cicli per evitare righe vuote indesiderate:

<ul>
{{- for item in items -}}
  <li>{{:item.name}}</li>
{{- endfor -}}
</ul>

19. Commenti

Aggiungi commenti ai template che non appariranno nell’output:

{{# Questo è un commento - non sarà renderizzato #}}
{{#
   I commenti multi-linea
   sono supportati
#}}

20. Controllo del Flusso

Statement Exit

Ferma il rendering del template anticipatamente:

{{if error_condition}}
  <p class="error">Si è verificato un errore</p>
  {{exit}}
{{endif}}

<p>Questo non sarà renderizzato se c'è un errore</p>

21. Best Practice e Performance

Compilazione dei Template

  • Compila i template una volta e riutilizza la versione compilata
  • Salva i template compilati su file per migliori prestazioni di avvio
  • Usa strategie di caching appropriate per ambienti di produzione

Uso dei Filtri

  • Usa i filtri built-in quando possibile (sono ottimizzati)
  • Minimizza filtri personalizzati complessi nei cicli
  • Considera di pre-elaborare i dati invece di logica template complessa

Uso delle Espressioni

  • Usa le espressioni per calcoli che altrimenti richiederebbero multiple istruzioni set
  • Evita espressioni estremamente complesse - dividile in più istruzioni set per leggibilità
  • Preferisci condizionali con espressioni per logica booleana complessa

Organizzazione dei Template

  • Usa l’ereditarietà per layout consistenti
  • Dividi template grandi in componenti più piccoli e riutilizzabili
  • Usa include con mappature per componenti parametrizzati
  • Organizza i template in strutture di directory logiche
  • Usa le macro per componenti ripetuti all’interno di un singolo template

Gestione degli Errori

Racchiudi le operazioni sui template in blocchi try-except per gestire errori di compilazione e rendering:

try
  lCompiledTemplate := lCompiler.Compile(lTemplate);
  lResult := lCompiledTemplate.Render;
except
  on E: ETProCompilerException do
    // Gestisci errori di compilazione (errori di sintassi, direttive non valide)
    ShowMessage('Errore di compilazione template: ' + E.Message);
  on E: ETProRenderException do
    // Gestisci errori di rendering (variabili mancanti, type mismatch)
    ShowMessage('Errore di rendering template: ' + E.Message);
  on E: Exception do
    // Gestisci altri errori
    ShowMessage('Errore inaspettato: ' + E.Message);
end;

TIP: Sviluppo vs Produzione In sviluppo, lascia propagare le eccezioni per vedere messaggi di errore dettagliati. In produzione, cattura e logga gli errori mostrando messaggi user-friendly. Considera un template di fallback per pagine critiche.


Progetti Open Source Correlati

TemplatePro si integra con altri progetti open source dello stesso autore:

Progetto Descrizione Integrazione
DMVCFramework Framework REST API per Delphi Rendering HTML server-side con serversideviews_templatepro e esempi HTMX
Delphi Fake Data Utils Generatore dati di test Genera dati di esempio realistici per anteprime e demo template
DelphiGuard Gestione memoria RAII Cleanup automatico per compiler e risorse template

Conclusione

TemplatePro è un motore di templating completo e potente che fornisce agli sviluppatori la flessibilità e il controllo necessari per lo sviluppo di applicazioni moderne. Le sue caratteristiche principali includono:

  • Sintassi Intuitiva: sintassi pulita e leggibile ispirata a motori popolari
  • Espressioni Potenti: calcoli inline, funzioni e logica booleana
  • Variabili Template: definisci e modifica variabili all’interno dei template
  • Condizionali Completi: condizioni basate su filtri e su espressioni
  • Cicli Flessibili: iterazione con pseudo-variabili e supporto continue
  • Ereditarietà dei Template: layout riutilizzabili e gerarchie di componenti
  • Include Parametrizzati: passa variabili ai template inclusi
  • Macro: blocchi di codice riutilizzabili con parametri
  • Filtri Concatenati: pipeline flessibili di trasformazione dati
  • Filtri Estesi: ricco set di filtri built-in più supporto per filtri personalizzati
  • Eccellenza JSON: supporto di prima classe per strutture dati JSON complesse
  • Type Safety: eccellente gestione del sistema di tipi Delphi inclusi i nullable
  • Design Modulare: inclusione template e sviluppo basato su componenti

Che tu stia costruendo semplici email HTML, applicazioni web complesse o sistemi di generazione report dinamici, TemplatePro fornisce gli strumenti necessari per creare template manutenibili, efficienti e potenti.


FAQ: Domande Frequenti

Qual è il miglior motore di template per Delphi?

TemplatePro è un motore di template potente e ricco di funzionalità per Delphi con sintassi ispirata a Jinja/Smarty. Supporta espressioni, condizionali, cicli, ereditarietà dei template, macro, filtri e dati JSON - tutto ciò di cui hai bisogno per generare HTML, email e report.

Come genero HTML in Delphi?

Usa TemplatePro:

uses TemplatePro;
var lCompiler := TTProCompiler.Create;
var lTemplate := lCompiler.Compile('<h1>Ciao {{:name}}!</h1>');
lTemplate.SetData('name', 'Mondo');
var HTML := lTemplate.Render;  // "<h1>Ciao Mondo!</h1>"

TemplatePro supporta l’ereditarietà dei template?

Sì, TemplatePro supporta l’ereditarietà dei template con la sintassi {{extends "base.tpro"}} e {{block "name"}}...{{endblock}}, simile a Jinja2. I template figli possono sovrascrivere blocchi specifici ereditando il resto.

Come uso le espressioni in TemplatePro?

Usa la sintassi {{@expression}} per calcoli e logica:

Totale: {{@quantity * price}}
{{set discount := @(total * 0.1)}}
{{if @(age >= 18)}}Adulto{{endif}}

Come imposto variabili nei template?

Usa lo statement {{set}}:

{{set counter := 0}}
{{set greeting := "Ciao"}}
{{set total := @(price * quantity)}}
{{set upper_name := :name|uppercase}}

Come passo variabili ai template inclusi?

Usa include con mappatura variabili:

{{include "component.tpro", title = "Il Mio Titolo", count = :item_count}}

Come gestisco l’escape HTML?

Per default, tutto l’output delle variabili È codificato HTML per sicurezza (prevenzione XSS). Caratteri come <, >, &, " sono automaticamente convertiti in entità HTML.

Per emettere HTML raw solo per contenuti fidati, usa:

{{:trusted_html$}}              {{# suffisso $ = output raw #}}
{{autoescape false}}
  {{:trusted_block}}            {{# blocco con autoescape off #}}
{{endautoescape}}

Sicurezza: Non disabilitare mai l’autoescape per dati forniti dagli utenti.

Cosa è successo ai filtri and e or?

I filtri and e or sono stati rimossi nella versione 1.0. Usa condizionali basati su espressioni:

{{# Vecchio modo (deprecato) #}}
{{if value1|and,value2}}...{{endif}}

{{# Nuovo modo #}}
{{if @(value1 and value2)}}...{{endif}}

TemplatePro è case-sensitive?

Dalla versione 0.7.0, TemplatePro è case insensitive sia per i nomi delle variabili che per le keyword delle direttive.

TemplatePro funziona con DMVCFramework?

Sì, TemplatePro si integra perfettamente con DMVCFramework per il rendering HTML server-side. Vedi gli esempi serversideviews_templatepro e htmx_website_with_templatepro.

TemplatePro è gratuito?

Sì, TemplatePro è gratuito e open-source sotto licenza Apache 2.0.


TemplatePro - Motore di template potente per Delphi. Ispirato a Jinja. Ricco di funzionalità. Open-source.

Versione Corrente: 1.1 - Aggiornato Gennaio 2026

Comments

comments powered by Disqus