Skip to content
English
  • There are no suggestions because the search field is empty.

Syntax Guide: Customized Reporting

This article explains how to build Word (.docx) templates using the custom template language. Templates are regular Word documents with embedded commands that get replaced at report-generation time.

Most important rule: Every command must be wrapped exactly like this:
#{ … }#
Missing the # characters is the #1 cause of broken templates and can be difficult to debug.

## Table of contents

Template data model
Common paths to use 
Loops - (loops over buildings, task contexts, access points) 
Conditional Content (IF blocks) 
Generating Images
Example Starter Template
Debugging Checklist



What data is available in a template?

When a user generates a report, they select:

  • a Site

  • one or more Building + Task Context + SSID combinations

One data object is built that your template can read. The root object looks like:

{ site: { id, name, buildings: [ { id, name, floorPlans: [{ id, name }], taskContexts: [ { id, type: "survey" | "design", name, ssid, createdBy, accessPoints: [ { id, displayName, floorPlanId, vendor?, mountType: "ceiling" | "wall" | "floor", modelName?, radios: [ { band: "2.4" | "5" | "6", channel, channelWidthMhz, bondedChannels: number[], powerDbm?, bsss: [ { macAddress?, ssid, basicBitrates: number[], supportedBitrates: number[], standards: WifiStandard[], isNonTransmitted?, isStandardPower? } ] } ] } ] ] } ] } ] } }

 

Common paths to use

  • site.name

  • site.buildings

  • $building.name

  • $building.floorPlans

  • $building.taskContexts

  • $taskContext.name, $taskContext.type, $taskContext.ssid, $taskContext.createdBy

  • $taskContext.accessPoints

  • $accessPoint.displayName, $accessPoint.mountType, $accessPoint.radios

  • $radio.band, $radio.channel, $radio.bsss

  • $bss.ssid, $bss.macAddress


Inserting values (JavaScript expressions)

Use #{ … }# to insert values into the document. The expression inside is JavaScript.

Example: simple text fields

Site: #{ site.name }#
 

Example: nested properties in a loop

Building name: #{ $building.name }#
Task type: #{ $taskContext.type }#
SSID: #{ $taskContext.ssid }#
 
 
Note: nested items are prefixed with a $ symbol (see next section).

FOR loops (repeat content)

Use FOR … IN … to loop over arrays. Inside a loop, you reference the current item with a $ prefix.

Loop over buildings

#{ FOR building IN site.buildings }#
Building: #{ $building.name }#
#{ END-FOR building }#
 

Loop over task contexts in each building 

#{ FOR building IN site.buildings }#
Building: #{ $building.name }#

#{ FOR taskContext IN $building.taskContexts }#
- Task: #{ $taskContext.name }# (#{ $taskContext.type }#)
SSID: #{ $taskContext.ssid }#
Created by: #{ $taskContext.createdBy }#
#{ END-FOR taskContext }#

#{ END-FOR building }#
 

Loop over access points

#{ FOR taskContext IN $building.taskContexts }#
Access Points:
#{ FOR accessPoint IN $taskContext.accessPoints }#
- #{ $accessPoint.displayName }# (Mount: #{ $accessPoint.mountType }#)
#{ END-FOR accessPoint }#
#{ END-FOR taskContext }#
 

Loop over filtered access points

You can use Javascript to filter the access points according to your needs, for instance to loop only over access points that have radios, use:

#{ FOR taskContext IN $building.taskContexts }#
Access Points:
#{ FOR accessPoint IN $taskContext.accessPoints.filter(ap => ap.radios.length > 0) }#
- #{ $accessPoint.displayName }# (Mount: #{ $accessPoint.mountType }#)
#{ END-FOR accessPoint }#
#{ END-FOR taskContext }#
 
Note: Make sure to end all of your FOR statements with END-FOR statements

IF blocks (conditional content)

Use IF … to include content only when a condition is true.

Example: only show model if it exists 

#{ IF $accessPoint.modelName }#
Model: #{ $accessPoint.modelName }#
#{ END-IF }#

 

Example: show something only for surveys

#{ IF $taskContext.type === 'survey' }#
This section applies to surveys only.
#{ END-IF }#
 
Note: Make sure to end all of your IF statements with END-IF statements 

Generating images in the DOCX

We provide a custom image(...) function that generates a report image and injects it into the document.

Syntax 

#{ IMAGE image({type: "primary", band: "5", buildingId: $building.id, taskContextId: $taskContext.id, taskContextType: $taskContext.type, floorPlanId: $floorPlan.id, ssid: $taskContext.ssid }) }#

This is a command, not just a value insert. You must include IMAGE and wrap everything with #{ … }#.

Image parameters

Parameter Type Required Notes
type "primary" | "secondary" | "cci"  Which report tool/output to render
buildingId number Usually $building.id
taskContextId number Usually $taskContext.id
taskContextType "survey" | "design" ✅  Best practice: pass $taskContext.type
band "2.4" | "5" | "6" Band to render
ssid string Usually $taskContext.ssid
floorPlanId number optional Use when the image is floor-plan specific
accessPointId number optional Use when the image is AP-specific
isThreeDimensional boolean optional If you want a 3D output (when supported)

Example: one image per floor plan, per task context

 #{ FOR taskContext IN $building.taskContexts }#
Task: #{ $taskContext.name }# (#{ $taskContext.type }#)

#{ FOR floorPlan IN $building.floorPlans }#
Floor plan: #{ $floorPlan.name }#

#{ IMAGE image({
type: "primary",
band: "5",
buildingId: $building.id,
taskContextId: $taskContext.id,
taskContextType: $taskContext.type,
floorPlanId: $floorPlan.id,
ssid: $taskContext.ssid
}) }#

#{ END-FOR floorPlan }#
#{ END-FOR taskContext }#

 


Practical “starter template” example

Copy/paste this into a Word document and adjust as needed:

 
Report for site: #{ site.name }#

#{ FOR building IN site.buildings }#
==================================================
Building: #{ $building.name }#
==================================================

Floor Plans:
#{ FOR floorPlan IN $building.floorPlans }#
- #{ $floorPlan.name }# (ID: #{ $floorPlan.id }#)
#{ END-FOR floorPlan }#

#{ FOR taskContext IN $building.taskContexts }#
----------------------------------------------
Task: #{ $taskContext.name }# (#{ $taskContext.type }#)
SSID: #{ $taskContext.ssid }#
Created by: #{ $taskContext.createdBy }#

Access Points:
#{ FOR accessPoint IN $taskContext.accessPoints }#
#{ $idx + 1 }#. #{ $accessPoint.displayName }# (#{ $accessPoint.mountType }#)
#{ END-FOR accessPoint }#

Primary (5 GHz) image:
#{ IMAGE image({
type: "primary",
band: "5",
buildingId: $building.id,
taskContextId: $taskContext.id,
taskContextType: $taskContext.type,
ssid: $taskContext.ssid
}) }#

#{ END-FOR taskContext }#

#{ END-FOR building }
 

Debugging checklist 

  1. Did you wrap every command exactly with #{ and }#?

  2. Did Word convert quotes to smart quotes (“ ” / ‘ ’)? Replace with normal quotes.

  3. Inside loops, did you use $ variables?
    Example: inside FOR building …, use $building, not building.

  4. Do your END-FOR names match?
    #{ END-FOR building }# must match #{ FOR building IN … }#

  5. If an image doesn’t render, confirm required fields exist: type, band, buildingId, taskContextId, ssid.

 

Need Something Else?

Still looking for a different reporting feature? Submit your request here.