Advanced Portal Designer Documentation
Index

Tag Reference Overview

APD uses a powerful template tag system that allows you to embed dynamic content, loop through data, create conditions, and interact with Business Central data directly in your HTML templates.

Tag Syntax

All APD tags use the following syntax:

<?tagname(parameters)?>

Where:

  • <? opens the tag
  • tagname is the tag function name
  • (parameters) contains the tag parameters
  • ?> closes the tag

Tag Categories

APD tags are organized into the following categories:

Category Purpose Examples
Data Tags Display and manipulate data field, filter, count
Display Tags Control output formatting field, calcdate, content
Control Flow Tags Loops and conditions loop, if, profile
Form Tags Create interactive forms key, action
Security Tags Control access profile, auth
Utility Tags Helper functions parm, setvalue, getvalue

Tag Compilation

APD templates are compiled before execution:

  1. Compile Time: Tags are parsed and validated
  2. Run Time: Compiled templates execute with current data
  3. Caching: Compiled templates are cached for performance

Compilation Errors

If a tag has invalid syntax:

  • Compilation fails
  • Error message indicates location
  • Template won't execute until fixed

Important Rules

No Nesting Tags

You cannot place a <??>tag inside another <??>tag. This is the most important syntax rule in APD templates.

<!-- WRONG - nested tags will NOT work -->
<?filter(Customer,"No.",<?parm(id)?>)?>
<?if(<?field(Customer,Balance)?>,'>', 0)?>
<?setvalue(Total,<?field(Item,"Unit Price")?>)?>

<!-- CORRECT - use expression functions instead -->
<?filter(Customer,"No.",Parm('id'))?>
<?if(Customer,Balance,'>',0)?>
<?setvalue(Total,field(Item,"Unit Price"))?>

Instead of nesting tags, use expression functions inside tag parameters. See Expression Functions below.

Quoting Table and Field Names

When a table or field name contains spaces or special characters (periods, parentheses, slashes, hyphens, etc.), you must enclose the name in double quotes.

<!-- Names without spaces or special characters - no quotes needed -->
<?open(Customer)?>
<?field(Customer,Name)?>
<?field(Item,Description)?>

<!-- Names WITH spaces or special characters - quotes required -->
<?open("Sales Header")?>
<?field(Customer,"No.")?>
<?field(Item,"Unit Price")?>
<?field(Customer,"Balance (LCY)")?>
<?filter("Sales Line","Document No.",field("Sales Header","No."))?>
<?open("Salesperson/Purchaser")?>
<?field(Customer,"E-Mail")?>

Rule of thumb: If the name contains anything other than letters, wrap it in double quotes.

Table and Field Numbers

Anywhere a tag accepts a Table or Field name, you can use the BC table number or field number instead. Production templates often mix both styles:

<!-- By name -->
<?open("Sales Header")?>
<?field("Sales Header","No.")?>

<!-- By number (Sales Header = 36, No. = 3) -->
<?open(36)?>
<?field(36,3)?>

<!-- The two forms work the same and can be mixed -->
<?open(Customer)?>
<?field(18,Name)?>
<?filter(18,1,Parm('custno'))?>

Names are easier to read; numbers are sometimes used for forms (the name="18:2" HTML attribute convention used by <?hidden?>/<?edit?>/APD_validate requires the numeric form).

Single-Quoted String Identifiers

For string identifiers (action codes, profile codes, parameter names, content names, memory keys, etc.) the convention is single quotes:

<?action('TASK.REGISTER.DAILY')?>
<?profile('CUSTOMER')?>
<?parse('_header.html')?>
<?parm('orderno')?>
<?content('about-company')?>
<?setvalue('Total',0)?>
<?getvalue('Total')?>
<?hasvalue('cart')?>

Quick Reference

Most Common Tags

Tag Purpose Example
field Display field value <?field(Customer,Name)?>
loop Iterate records <?loop(Item,'-')?>...<?endloop(Item)?>
if Conditional display <?if(Customer,Balance,'>',0)?>...<?endif?>
parm Get URL parameter <?parm(id)?>
open Open data table <?open(Customer)?>
filter Filter records <?filter(Customer,"No.",10000)?>
key Build URL query fragment for primary key (use inside <a href> / form action URLs only) <a href="?action=DETAIL&<?key(Customer)?>">
content Include content <?content(article-name)?>
action Link to action <?action(MY-ACTION)?>

Expression Syntax

Expressions live inside the parameter list of a tag — not at the tag-output level. .. is the string-concatenation operator (Lua-style), and + - * / are arithmetic operators. Expressions can call the expression functions like field(Table,Field), Parm('name'), no(), today(), etc.

<!-- Multiple field tags in HTML: just put literal text between them -->
<h2><?field(Customer,Name)?> - <?field(Customer,City)?></h2>

<!-- To evaluate an expression and OUTPUT the result, use <?calc?> -->
<?calc(field(Item,"Unit Price")*field(Item,Quantity))?>
<?calc(field(Item,"Unit Price")*field(Item,Quantity),'<Precision,2:2>')?>

<!-- Expressions in filter values: equality is the bare expression -->
<?filter(Customer,"No.",Parm('id'))?>
<?filter("Sales Line","Document No.",field("Sales Header","No."))?>

<!-- Building a filter value via concatenation -->
<?filter(Customer,Name,'*'..Parm('search')..'*')?>
<?filter("task subscriber",Email,'@'..userid()..'@example.com')?>

<!-- Storing a computed value with <?setvalue?> -->
<?setvalue(FullName,field(Customer,Name)..' ('..field(Customer,"No.")..')')?>

<!-- Combining inside a view string (passed to <?table?> / <?open?>) -->
<?table("Sales Line",'where("Document No."=0('..field("Sales Header","No.")..'))')?>

Common mistake: <?field(Customer,Name)..' - '..field(Customer,City)?> is not valid — <?field?> is a tag, and tag outputs cannot be combined with ... To concatenate field values into one output, either write them as separate tags with literal HTML between them, or wrap the expression in <?calc?> / <?setvalue?>.

Data Context

Opening Tables

Before using field tags, open the table:

<?open(Customer)?>
<?filter(Customer,"No.",10000)?>
<?findfirst(Customer)?>
<h1><?field(Customer,Name)?></h1>

Loop Context

Inside loops, the current record is automatically available:

<?loop(Item,'-')?>
    <tr>
        <td><?field(Item,"No.")?></td>
        <td><?field(Item,Description)?></td>
        <td><?field(Item,"Unit Price")?></td>
    </tr>
<?endloop(Item)?>

Tag Parameters

Parameter Types

Type Description Example
Table Name Business Central table Customer, "Sales Header"
Field Name Field in table Name, "No.", "Unit Price"
Literal Value Fixed text/number 'Hello', 100
Expression Calculated value field(Item,Qty)*2
Format String Output format <Precision,2:2>

Optional Parameters

Many tags have optional parameters:

<!-- Basic field output -->
<?field(Customer,Name)?>

<!-- Field with format -->
<?field(Item,"Unit Price",'<Precision,2:2><Standard Format,0>')?>

<!-- Field with HTML encoding disabled -->
<?field(Item,Description,,false)?>

Combining Tags with Control Flow

Tags can be combined with control flow for complex logic. Note that the if tag uses its own parameters (table, field, operator, value) - NOT nested tags:

<?if(Customer,Balance,'>',1000)?>
    <span class="warning"><?field(Customer,Balance)?></span>
<?else?>
    <span><?field(Customer,Balance)?></span>
<?endif?>

Remember: each <?...?> tag stands on its own. You never place one inside another.

Tag Processing Order

  1. Template loaded
  2. Includes resolved (<?include?>)
  3. Opens and filters executed
  4. Loops iterate
  5. Conditions evaluated
  6. Fields resolved
  7. Output generated

Best Practices

Performance

  • Open tables once, not in loops
  • Use specific filters to limit data
  • Avoid unnecessary nested loops

Readability

  • Use consistent indentation
  • Comment complex logic
  • Group related tags

Security

  • Use security profiles for sensitive data
  • Validate user input
  • Apply table-level security filters

Debugging Tags

Common Issues

Problem Cause Solution
Empty output No data found Check filters
Wrong value Field name typo Verify field name
Error Invalid tag syntax Check parameters
No loop Table not opened Add <?open()?>

Testing Tips

  1. Start simple, add complexity
  2. Test each section separately
  3. Check compile errors
  4. Verify data exists

Expression Functions

Since you cannot nest <??>tags, use these expression functions inside tag parameters to access dynamic values. String concatenation is done with .. (double dot, like Lua).

Available Functions

Function Description Example
field(Table,Field) Get field value field(Customer,Name)
Parm('name') Get URL/POST parameter Parm('id')
today() Current date today()
time() Current time time()
count(Table) Record count count(Item)
no() User's BC entity number no()
abs(n) Absolute value abs(field(Item,Inventory))
calcdate(formula,date) Calculate date calcdate('-1M',today())
getvalue(key) Get session memory value getvalue('Total')
sessionid() Current session ID sessionid()
Company() User's APD company code Company()
CompanyName() BC company name CompanyName()
Empty() Returns two single quotes (for filtering) Empty()
ping() Returns a single quote character ping()

Expression Examples

<!-- Use Parm() instead of nesting <?parm()?> -->
<?filter(Customer,"No.",Parm('custno'))?>

<!-- Use field() instead of nesting <?field()?> -->
<?filter("Sales Line","Document No.",field("Sales Header","No."))?>
<?setvalue(CustomerName,field(Customer,Name))?>

<!-- Use no() instead of nesting <?no?> -->
<?filter(Customer,"No.",no())?>

<!-- Use getvalue() for accumulation -->
<?setvalue(Total,getvalue('Total')+field("Sales Line",Amount))?>

<!-- String concatenation with .. -->
<?setvalue(FullName,field(Customer,Name)..' ('..field(Customer,"No.")..')')?>

<!-- Arithmetic expressions -->
<?calc(field(Item,"Unit Price")*field(Item,Quantity))?>