TemplatePro Guida per Sviluppatori
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.
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ù eccezioniEInvalidCast. I valori null producono una stringa vuota. - TField null nei filtri: I valori
TFieldnull 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
IExprEvaluatore 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 operatoriand/or - Elseif/Elif
{{elseif}}/{{elif}}- Rami condizionali multipli senza annidamento - Formato ISO 8601 di Default - I filtri
datetostredatetimetostrusano 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,jsonper codifica URL, troncamento testo e serializzazione JSON - Performance Migliorate - Codebase rifattorizzato con esecuzione filtri ottimizzata
Nota: I filtri
andeorsono 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
.tpccon 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
defaultper 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
setper 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 primaa + 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
datetostrusayyyy-mm-ddcome formato predefinito, mentredatetimetostrusayyyy-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 aSetData()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à
- Ereditarietà a singolo livello: i template figli possono estendere solo un template padre
- Override dei blocchi: se un figlio definisce un blocco esistente, sovrascrive quello del padre
- Blocchi default: se un figlio non definisce un blocco, viene usato il contenuto default del padre
- 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.tproche 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à: <div>Ciao</div>
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): <b>Grassetto</b>
Autoescape off: <b>Grassetto</b>
Torna al default: <b>Grassetto</b>
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.
Link e Risorse
- Repository GitHub TemplatePro
- Unit test per esempi completi e casi limite
- Gruppo di Supporto DelphiMVCFramework su Facebook (include supporto TemplatePro)
- Supporta il Progetto su Patreon
- Documentazione precedente
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