Dynamic or advanced customization of the fill-in form is needed, and Viz Pilot Edge allows this through template scripting. Scripts are written in TypeScript, and access to the template is provided via a Script API named vizrt
.
It allows users to customize how templates look and behave, as well as fill in values from external sources. This section describes how to use the script editor, and how to access the values of the fields supported in Template Builder.
These are the following topics:
Script Technology and Security
The script language in the template editor is TypeScript. All JavaScript is valid Typescript, so you can choose what you want inside the editor, but the syntax highlighting and the error checking expects Typescript. The script inside the editor is automatically compiled into JavaScript and stored both as Typescript and JavaScript inside the template. When a template script normally executes in the browser, it is executed through the browser’s Web API.
When executing scripts through the browser, security is subject to the browser's default security policies. This includes:
CORS (Cross-Origin Resource Sharing): Requests to external servers may be blocked if the correct CORS headers are not set.
Same-Origin Policy: Scripts can only interact with resources from the same domain unless explicitly permitted.
Sandboxing: If hosted within an iframe, additional restrictions may apply depending on the host’s configuration.
To avoid unexpected issues, ensure that your server is properly configured to allow cross-origin access if needed.
Fetching Data from External Servers
If your script fetches data from external sources (for example, sports statistics or news feeds) and these servers do not support CORS, you must:
Use a proxy server to relay the request.
Make the request through the proxy, which must be configured to handle the external API call and return the data with appropriate CORS headers.
This ensures that your application can access external data while adhering to browser security policies.
The Script Editor
The script editor is available in the "Fill-in Form" tab of Template Builder. It can be used docked or undocked from the Template Builder. While undocked, you can adjust the size of the window for a smoother experience.
The script editor also provides error messages depending on the problem. It shows compile or run time errors.
Compile Error
Runtime Error
When trying to catch a runtime error, it is recommend that you name a function with a string value. By naming a function, this name is used in the error message to indicate where the error came from.
In the following example, if you catch an error, the string used under "user defined name" is shown in the error message:
In this case, you can just add the string value in your function error report so it shows in the error message:
Initialization
There are two global events that can be used to initialize the Fill-in Form:
onCreate: Called when template is opened in Viz Pilot Edge.
Note: This event is not triggered when creating a new data-element from an existing one.
Example:
vizrt.onCreate = () => {
// For example set startup values, initialize fields visibility, etc.
Initialize()
}
onLoad: Called when an existing data-element is loaded in Viz Pilot Edge. The normal steps are to initiate/refresh data each time you open a data-element.
Note: This event can potentially modify the data-element when opening, which means it must be saved before being draggable/sendable to a NRCS.
Example:
vizrt.onLoad = () => {
// For example reset or refresh values, etc.
ResetForm()
}
Info: These events must be defined in the Template Builder's script, but they are not triggered in Template Builder.
Jump to Preview Point
To refresh the preview, or jump to a specified preview point in the current graphics, use the vizrt.jumpToPreviewPoint method with a named preview point as a parameter to the method. Sending an empty string, jumps to the default preview point in the scene.
vizrt.onClick = (name: string) => {
if
(name ===
"jump2"
) {
console.log(
"jumping to preview point 2"
)
vizrt.jumpToPreviewPoint(
"pilot2"
)
}
}
Temporary Storage
In some scenarios, temporary storage beyond standard script variables, is useful. This storage functions similarly to a field in the model and can be referenced as a source in a Dynamic Drop-Down.
Using vizrt.$data
A special object, vizrt.$data
, is available in scripting. This object acts as a key-value map where you can freely define your own keys (the values must be strings).
vizrt.$data.mykey =
"myvalue"
In this example, the key mykey
is assigned the value "myvalue"
.
Dynamic Drop-Down Integration
You can use a key in the $data object as a source for Dynamic drop-down, for instance $data.mykey
, replacing the use of a traditional model field. The source data is not stored in the payload.
vizrt.$data.mykey =
"[{"
label
": "
Tottenham Hotspur
", "
value
": "
tottenham
"}, {"
label
": "
Liverpool
", "
value
": "
liverpool
"}, {"
label
": "
Manchester City
", "
value
": "
mancity
"}]"
See also Dynamic Drop-Down.
Field Access
When using the scripting tool in the template, the individual fields must be accessed through the global name space vizrt.fields (for example, vizrt.fields.$singleline.value).
Note: Writing $singleline.value instead of vizrt.fields.$singleline.value does not work, and gives a Compile Error.
The script executes when a graphic element is opened or created with the scripted template in Viz Pilot Edge.
In Template Builder, the script is also re-loaded and restarted when there are changes made to it.
By typing vizrt.fields, the editor's autocomplete shows you the available fields to choose from.
You can read and write field values, as well as react to value changes from outside the script, and access the properties error, hidden, readOnly and tip of the vizrt
fields.
onChanged: A property on fields that you can set as a function, and if you do so, this function is called whenever the value of the fields changes, and gets the new value as an argument . If this is not set, it is null.
Note: Changes done to field values by the template script do not trigger the onChanged function to be called.
readOnly: Read and write boolean access, to whether the field should be editable in the form or not. If false , the field and its input elements are editable in the UI. If true , they are read-only and greyed out in the UI, but are accessible, saved and loaded as part of the payload.
hidden: Read and write boolean access, to whether the field should be editable in the form or not. If false , the field and its input elements are present and visible in the UI. If true , they are hidden from the UI but are accessible, saved and loaded as part of the payload.
error: Read and write string access, to an error to display for this field. It overrides other error messages associated with the field when non-empty (e.g. errors due to input length or regex constraints specified in the field definition).
tip: Read and write string access, to a tip to use for this field. It overrides the tip specified in the field definition when non-empty.
Note: Dashes cannot be used in Typescript with the dot syntax, instead you can use vizrt.fields["$01-week"] syntax to be able to access it.
Typescript lets you access fields using known names (for example, vizrt.fields["$field_2"]), but does not allow expressing the field names using variables (for example, vizrt.fields["$field_" + num]), as it is unable to determine whether the field name is valid and what type the field is. To overcome this, the type checking associated with vizrt.fields can be locally ignored by using the any type. You may do so inline using for example (vizrt.fields as any)["$field_" + num], or storing it as a new variable, as shown in the example below.
Note: Be aware that when using an object cast to any, the script editor isn't able to help you catch errors like setting a boolean value to a string field, or even trying to access a field that does not exist..
Accessing Concepts & Variants from Scripting
To access the information from concept and variants fields, because they contain dashes, you must use square brackets, as shown in the example below.
//When the Concept is changed, get its value and put it in a text field with field name info1
vizrt.fields[
"$-concept-variant-choice"
].$concept.onChanged = () =>
{vizrt.fields.$info1.value = vizrt.fields[
"$-concept-variant-choice"
].$concept.value }
//When the Variant is changed, get the value and put it in a text field with field name info2
vizrt.fields[
"$-concept-variant-choice"
].$variant.onChanged = () =>
{vizrt.fields.$info2.value = vizrt.fields[
"$-concept-variant-choice"
].$variant.value }
External Sources
Whether on template load, or as a reaction to a field change, you can initiate HTTP, HTTPS or REST calls to fetch values from third party or external services.
This can easily be done via the browser's built-in fetch API: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API.
Info: See the Quick Start Examples section for a short example of a REST call triggered by an onChanged event.
Image Metadata
Every image has some amount of metadata attached to it, and with this field you are able to access this metadata by using the script editor.
You can upload images and the corresponding metadata to asset source servers. By accessing an image's metadata, you can auto-fill the name field within a template or alternatively display or hide an image that might be copyrighted.
Note: Image scripting metadata currently works for images retrieved from the following asset source servers: Vizone, Vos, GH and OMS.
How to Use the Image Metadata
If you are using a newly created template, simply choose any image, and then query that image's metadata in the script editor by querying the image's metadata map. With an existing template, which already contains an image that was created before the 2.4 version of Template Builder and Pilot Edge, then simply click on the current image and re-select it from the asset selector, or alternatively select another random image and then select back the original one. Once this is done, you can proceed by querying the image's metadata map.
This example checks if imageName has a metadata key named test and then tries to get the value of that metadata key. You can use the script syntax shown below:
let hasMetadataKey: boolean = vizrt.fields.$imageName.metadata.has(
"test"
)
//true if the metadata contains the key test
let metadataValue: string = vizrt.fields.$imageName.metadata.get(
"test"
)
//it is set to the value it has in the metadata, otherwise it is undefined
This code example reacts when a new image is selected. When the image2 field gets assigned a new image, it tries to get the description from the metadata associated with the new image, and set it into the text field img2_txt. If the description does not exist, a message displays explaining it was not found.
vizrt.fields.$image2.onChanged = () => {
if
(vizrt.fields.$image2.metadata != undefined) {
let keyName =
"description"
let a = vizrt.fields.$image2.metadata.get(keyName)
// get the metadata value that has the given key
if
(a != undefined) {
vizrt.fields.$img2_txt.value = a
// if the value is not undefined, then set it into a string field within the template
}
else
{
vizrt.fields.$img2_txt.value =
"The key '"
+ keyName +
"' was not found inside the metadata map"
// Alternatively, set it to nothing: vizrt.fields.$img2_txt.value = ""
}
}
}
To access the entire unprocessed/unparsed metadata file, use wholeMetadataString. This can be useful for debugging, or for finding the keys available in the metadata:
let rawMetadata:string = vizrt.fields.$imageName.metadata.get(
"wholeMetadataString"
)
Image Metadata XML
An image's metadata is stored within asset source servers in XML format, and the XML metadata structure should follow a simple field-value (key-value) structure. This is to guarantee that all the metadata is correctly mapped and made accessible through the script editor.
However, since many image metadata XMLs are disorderly, a parser has been created to handle most XML structures, although this has some consequences that should be made aware of. All these example scripts are based on an image field named "image1".
Empty field-value pairs get added accordingly:
<field name=
"car"
/>
<field name=
"color"
>
<value/>
</field>
// Accessing these can be done using:
let a = vizrt.fields.$image1.metadata.get(
"car"
)
let b = vizrt.fields.$image1.metadata.get(
"color"
)
// Both a and b will be ""
Nested structures get stored based on their hierarchy, with "/" being the parent-child separator:
<field name=
"access-rights"
>
<field name=
"user-rights"
>
<value>
true
</value>
</field>
</field>
// To access the user-rights value:
let a = vizrt.fields.$image1.metadata.get(
"access-rights/user-rights"
)
// a will then be set to true.
Any fields with duplicate names get assigned a unique name with an incrementing suffix:
<
field
name
=
"file-link-id"
>
<
value
>id123</
value
>
</
field
>
<
field
name
=
"file-link-id"
>
<
value
>id456</
value
>
</
field
>
<
field
name
=
"file-link-id"
>
<
value
>id789</
value
>
</
field
>
Access duplicate names like this using the incrementing suffix:
let a = vizrt.fields.$image1.metadata.get(
"file-link-id"
)
let b = vizrt.fields.$image1.metadata.get(
"file-link-id(2)"
)
let c = vizrt.fields.$image1.metadata.get(
"file-link-id(3)"
)
a will be
"id123"
b will be
"id456"
c will be
"id789"
Read Only Fields
Some fields are currently supported only for read-access by the scripting API. These are the following:
Duplet
Triplet
Map
Image
Video
For the Image and Video fields, the script is able to access some properties (their height, width, etc.) from the file.
The following example shows how to retrieve the image height:
vizrt.fields.$ImageInfo.value =
"No image info"
;
vizrt.fields.$image.onChanged =() => {
vizrt.fields.$ImageInfo.value =
'Image changed'
;
var v = vizrt.fields.$image.value;
if
(v != undefined && v.height != undefined)
vizrt.fields.$ImageInfo.value = v.height.toString();
else
vizrt.fields.$ImageInfo.value =
"No image info"
;
}
Note: Because images and videos can be undefined, they must be checked before they are used.
Unsupported Fields
As of now, all List and Table fields are unavailable from the scripting API.