File Action
File actions serve HTML templates with embedded APD tags that dynamically pull data from Business Central. This is the most common action type for building portal pages.
Overview
A File action:
- Serves an HTML template file
- Processes APD tags (like
<?field()?>, <?loop()?>) - Returns the resulting HTML to the browser
- Supports multi-language template variations
When to Use File Actions
Use File actions for:
- Web pages with dynamic data
- Customer/vendor portals
- Order entry forms
- Report dashboards
- Any HTML-based content
Creating a File Action
Step-by-Step
- Open the Advanced Portal Designer menu page (search for it in Tell Me) and click Actions
- Click New
- Enter the Web Action code
- Set Type to "File"
- In the HTML/XML Template File field, enter a template name
- If the template doesn't exist, you'll be prompted to create it
- Edit and save your template
- Compile the action
Template File Field
The template file name:
- Should be descriptive (e.g., "orders-list.html")
- Doesn't need the full path
- Can include file extension or not
- Is case-insensitive
Template Structure
Basic Template
Reminder: APD tags cannot be nested. Where you need a parameter value inside another tag, use the
Parm('name')expression function (and similar functions likefield(Table,Field),no(),today()) — not a nested<?parm?>tag.
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
<script src="<?action('apdscript')?>"></script>
</head>
<body>
<h1>Welcome, <?field(Customer,Name)?></h1>
<?open("Sales Header")?>
<?filter("Sales Header","Sell-to Customer No.",Parm('custno'))?>
<?loop("Sales Header",'-')?>
<div class="order">
<p>Order: <?field("Sales Header","No.")?></p>
<p>Date: <?field("Sales Header","Order Date")?></p>
</div>
<?endloop("Sales Header")?>
<?close("Sales Header")?>
</body>
</html>
Tag Syntax
APD tags follow this pattern:
<?tagname(parameter1, parameter2, ...)?>
Tags are case-insensitive.
Multi-Language Support
Language Variations
Create language-specific template variations:
- Main template:
orders.html(default language) - German variant: Create with subpath "1031"
- French variant: Create with subpath "1036"
How It Works
- APD checks user's language preference
- Looks for template with matching language subpath
- Falls back to default template if not found
The Template Editor
Opening the Editor
- In the action card, click the HTML/XML Template File field
- Click the AssistEdit button (...)
- The template editor opens
Editor Features
| Feature | Description |
|---|---|
| Syntax highlighting | HTML and APD tag highlighting |
| Intellisense | Auto-complete for tags, tables, fields |
| Search | Find text in template |
| Search & Replace | Find and replace text |
Saving Changes
- Make your edits
- Click Save in the editor
- The template is stored in Business Central
- Compile to apply changes
Including Other Templates
Use the <?parse()?> tag to include other templates:
<?parse('header.html')?>
<div class="content">
Your main content here
</div>
<?parse('footer.html')?>
This allows for:
- Reusable header/footer templates
- Component-based design
- Consistent styling across pages
Common Template Patterns
Data Display Page
<?open(Customer)?>
<?get(Customer,Parm('no'))?>
<h1><?field(Customer,Name)?></h1>
<p>Address: <?field(Customer,Address)?></p>
<p>City: <?field(Customer,City)?></p>
<?close(Customer)?>
List Page with Loop
<?open(Item)?>
<?filter(Item,Blocked,false)?>
<?loop(Item,'-')?>
<tr>
<td><?field(Item,"No.")?></td>
<td><?field(Item,Description)?></td>
<td><?field(Item,"Unit Price")?></td>
</tr>
<?endloop(Item)?>
<?close(Item)?>
Form with Validation
<form name="customer_form">
<?open(Customer)?>
<?get(Customer,Parm('no'))?>
<input type="text"
name="18:2" <!-- Table:Field -->
value="<?field(Customer,Name)?>"
onchange="APD_validate(this,18,2)">
<?close(Customer)?>
</form>
Conditional Content
<?auth()?>
<p>Welcome, <?field(Customer,Name)?></p>
<?else?>
<p>Please <a href="?action=LOGIN">log in</a></p>
<?endif?>
Override MIME Type
For non-HTML output:
| MIME Type | Use Case |
|---|---|
| application/json | JSON output |
| application/xml | XML output |
| text/plain | Plain text |
| text/css | CSS stylesheets |
Set in the Override Mime Type field on the action.
Compilation
Why Compile?
Compilation:
- Validates tag syntax
- Resolves table and field names
- Creates optimized execution path
- Catches errors before runtime
Compilation Errors
Common compilation errors:
| Error | Cause | Solution |
|---|---|---|
| Missing ?> | Unclosed tag | Add closing ?> |
| Unknown table | Table name misspelled | Check table name |
| Unknown field | Field name misspelled | Check field name |
| Missing endif | If without endif | Add |
| Missing endloop | Loop without endloop | Add <?endloop(TableName)?> (the table-name argument is required) |
Viewing Compiled Data
To see compiled template data:
- Open the Advanced Portal Designer menu and click Precompiled Data (or the equivalent maintenance entry)
- Filter by your action code
- Review the compiled instructions
Performance Tips
Caching
Enable Cacheable for:
- Static pages
- Images and CSS
- Infrequently changing content
Efficient Loops
- Use filters to limit records
- Avoid nested loops when possible
- Use paging for large datasets
Template Size
- Split large templates into includes
- Move JavaScript to separate files
- Use external CSS files
Troubleshooting
Template Not Found
- Verify template name matches exactly
- Check template exists in Templates list
- Ensure no typos in action configuration
Tags Not Processing
- Verify compilation succeeded
- Check for syntax errors
- Ensure tables are opened before use
Data Not Displaying
- Check table filters
- Verify field names
- Test with simpler template first