VOGO Voice – Knowledge Base

Template Engine

Estimated reading time: 9 min

The purpose of the template engine is to allow more complex expressions, logic, and dynamic content to be generated in order to create any type of custom skill. We make use of the Handlebars Engine with a few added features that allow us to run more complex functions. This article should encompass all that is needed we do encourage you to read more on Handlebars if you are curious about how the engine works.

Syntax & Data

When wanting to reference any data within a response card or many other components that support templates it is simply adding double open {{ and closing }} curly brackets to the text. Let us say I created an intent and interaction that looked something like “My favorite color is {myColor}”. If this was my intent I set up then I know that if I wanted to repeat that in my “Response Card” component in an interaction I could reference it by typing I also like the color {{inputs.myColor.value}}. and this would replace the {{ section }} with the color spoken to be I also like the color blue. We have a wide variety of data that can be referenced and suggest reading up on our Data Breakdown Guide for all of the different values.

Simple If/else

The next most common situation is when the response may be depending on a value or the display on the screen needs to say something if the value is one or another. In these cases an If/else if most common and can be used as shown.

Data:
{
  isActive: true
}

Template:
{{#if isActive}}
  It is active.
{{else}}
  It is not active.
{{/if}}

There are cases when you will want to have an if/elseIf/else logic and can be done in the manner below.

Data:
{
  isActive: true,
  isEnabled: true,
}

Template:
{{#if isActive}}
  It is active.
{{else if isEnabled}}
  It is enabled but not active.
{{else}}
  It is not active nor enabled.
{{/if}}

Advanced If/else

For more advanced used cases where you need to test something beyond a simple exists or boolean expression we also support all the normal conditional logic. Use any of the values in the list as shown in the examples.
Compare types are:

OperatorReason
!=Does not equal (Not Strict Comparison)
!==Does not equal (Strict Comparison)
<Less than
<=Lean than or equal to
==Equals (Not Strict Comparison)
=== or = (shorthand)Equals (Strict Comparison)
>Greater than
>=Greater than or equal to
noneOf The right argument is not included in the left. Typically used for value in an array.
Reference
oneOf The right argument is included in the left. Typically used for value in an array.
Reference
typeof Compares if the left and right types are the same.
{{#if key operator value}}

Data:
{
  count: 1
}

Examples:
{{#if count '===' 0 }}
{{#if count '===' 1 }}
{{#if count '>' 1 }}

Evaluation Context

each and with let you switch context to simplify your temple. Given the below example you can reference inner keys by simply change the context.

Data:
{
  person: {
    firstname: "Yehuda",
    lastname: "Katz"
  }
}

Tempalte:
{{#with person}}
{{firstname}} {{lastname}}
{{/with}}

When using the each syntax {{this}} represents the value of the array context it is looping over.

Data:
{
  people: [
    "Yehuda Katz",
    "Alan Johnson",
    "Charles Jolley"
  ]
}

Template:
{{#each people}}
  {{this}}
{{/each}}

If the array is of objects then you would want to adjust the syntax slightly. See the following example.

Data:
{
  people: [
    { "first": "Yehuda", "last": "Katz" },
    { "first": "Alan", "last": "Johnson" },
    { "first": "Charles", "last": "Jolley" }
  ]
}

Template:
{{#each people}}
  {{first}} {{last}}
{{/each}}

Random Value

There are cases where we would like to randomly pick a value from a list of various results. We can do this with the following syntax.

{{random Array}}

Data:
{ 
  welcomeList: ["Welcome", "Hi", "Good day"]
}

Examples:
{{random welcomeList}}

Parsing String into JSON (jsonParse)

There are cases where the text of a previous result was not an object but a string representing JSON. There are other cases when you want to create your own Array or JSON object. In both cases, you can use the jsonParse to easily access this information. Below are a few examples.

Context Example:
{{#with (jsonParse '{"text":"Success"}') }}
{{text}}
{{/with}}

Results:
Succcess

Loop Example:
{{#each (jsonParse '[{"text":"Success 1"}, {"text":"Success 2"}]') }}
{{text}}
{{/each}}

Results:
Success 1 Success 2

Show List Example:
{{#showList (jsonParse '[{"text":"Success 1"}, {"text":"Success 2"}]') }}
{{text}}
{{/showList}}

Results:
Success 1 and Success 2

Random Result from Array
{{random (jsonParse '["Success 1", "Success 2"]') }}

Results: Can be either value randomly

Random Result from Object
{{#with (random (jsonParse '[{"text":"Success 1"}, {"text":"Success 2"}]')) }}
{{text}}
{{/with}}

Results: Can be either value randomly

Showing Lists

There are cases where you will want to create a list like A, B, and C or A, B, or C or A|B|C. In all of these cases, it can be tricky to create this expression and this is where the showList function comes in handy. Follow the examples below for creating various lists.

Basic Syntax: {{#showList Array}}{{this}}{{/showList}}
Basic Syntax: {{#showList Array}}{{field1}} {{field2}}{{/showList}}
Advanced Syntax: {{#showList Array Options}}{{this}}{{/showList}}
Advanced Syntax: {{#showList Array Options}}{{field1}} {{field2}}{{/showList}}

Data:
{
  list: ["A", "B", "C"]
  people: [
    { "first": "Yehuda", "last": "Katz" },
    { "first": "Alan", "last": "Johnson" },
    { "first": "Charles", "last": "Jolley" }
  ]
}

Template:
{{#showList list}}{{this}}{{/showList}}
{{#showList list lastWord="or"}}{{this}}{{/showList}}
{{#showList list lastWord="" join="; "}}{{this}}{{/showList}}
{{#showList list lastWord="" join="|"}}{{this}}{{/showList}}
{{#showList people}}{{first}} {{last}}{{/showList}}

Results:
A, B, and C
A, B, or C
A; B; C
A|B|C
Yehuda Katz, Alan Johnson, and Charles Jolley

Saying an Email Address

There are times when you will want to convert an email address into something

Data:
{
  email: "contact@vogovoice.com"
}

Template:
{{sayEmail email}}
{{sayEmail 'contact@vogovoice.com'}}
{{sayEmail 'john.doe@gmail.com'}}

Results:
contact at vogovoice dot com
john dot doe at gmail dot com

Pluralize

In many cases, you may not know if you have 0, 1 or more in the results and it can be complicated to say there 0 results or 1 results or 50 results and it would be helpful to automate this. This is when you will want to use the pluralize features. See the examples below.

Syntax: {{pluralize Integer 'String'}}

Data:
{
  connectors: {
    c1: {
      first: Object,
      length: 0
    },
    c2: {
      first: Object,
      length: 1
    },
    c2: {
      first: Object,
      length: 50
    }
}

Template:
You have {{connectors.c1.length}} {{pluralize connectors.c1.length 'result'}}.
You have {{connectors.c2.length}} {{pluralize connectors.c2.length 'result'}}.
You have {{connectors.c3.length}} {{pluralize connectors.c3.length 'result'}}.

Results:
You have 0 results.
You have 1 result.
You have 50 results.

mod

When there are cases where you want to use a Math mod to determine if something should happen within a template you can use the following syntax. This can be useful when trying to determine even or odd numbers, wanting to show something every nth time.

{{mod base divisor}}

Data:
{
  input1: 2,
  input2: 3
}

Template:
{{#if (mod input1 2) '===' 0}}{{input1}} is an even number.{{else}}{{input1}} is not an even number. It must be odd.{{/if}} 
{{#if (mod input2 2) '===' 0}}{{input2}} is an even number.{{else}}{{input2}} is not an even number. It must be odd.{{/if}}

Results:
This is an even number.
This is not an even number. It must be odd.

lookup

It is used to lookup properties of object based on data from the input.  In the following example we use lookup to get the country and name from the cities object using the resident-in from the persons array.


Data:
  "var": {
   
    "persons": [
      {
        "name": "Nils",
        "resident-in": "darmstadt"
      },
      {
        "name": "Yehuda",
        "resident-in": "san-francisco"
      }
    ],
 "cities": {
      "darmstadt": {
        "name": "Darmstadt",
        "country": "Germany"
      },
      "san-francisco": {
        "name": "San Francisco",
        "country": "USA"
      }
    }
  }


Template: 
{{#each var.persons}}
    {{name}} lives in {{#with (lookup ../var.cities [resident-in])}}
      {{name}} ({{country}})
    {{/with}}
{{/each}}

Results:
   Nils lives in Darmstadt (Germany)
   Yehuda lives in San Francisco (USA)

unless  

It is the opposite of the “if” statement. This block is executed if it returns a false value. Below are a few examples.

Data:
 "var": {
         }

Template:
Welcome to test page.{{#unless var.item}}
This page does not have any values.
{{/unless}}

Results:
 Welcome to test page.
 This page does not have any values.

Another Example

Data:
  "var": {
       "item":   value 
          }

Template:
Welcome to test page.{{#unless var.item}}
This page does not have any values.
{{/unless}}

Results:
Welcome to test page.

Subexpressions

Subexpressions are used to write an expression inside another expression or for writing nested expressions. Below are a few examples.

Data:
 "var": {
  "a": 1,
  "b": 1
        }

Template:
 {{#if (add var.a var.b) '==' '2'}}Correct value{{else}}Wrong value{{/if}}

Results:
Correct value

Another Example
Data:
 "var": {
  "a": 1,
  "b": 1
        }

Template: 
 {{#if  (isNumber var.a) }} Correct value{{else}}Wrong value{{/if}}

Results:
Correct value

Display Functions

Below are a few functions to convert characters in the expression to the desired format.

1. capitalizeAll

 It is used to capitalize the first letter of each word.

Data:
 "var": {
 "case": "hello world"
  }

Template:
 {{capitalizeAll 'hello world'}}
 {{capitalizeAll var.case}}

Results:
Hello World

 2. capitalize

Used to capitalize the first letter of a sentence. 

Data:
  "var": {
 "case": "hello world"
  }
 
Template:
 {{capitalize 'hello world'}}
 {{capitalize var.case}}

Results: 
Hello world

3. uppercase

Used to convert all the text to uppercase.

Data:

 "var": {
 "case": "hello world"
 }

Template:
{{uppercase 'hello world'}}
{{uppercase var.case}}

Results:
HELLO WORLD

4. lowercase

 Used to convert all the text to lowercase.

Data:
  "var": {
 "ucase": "HELLO WORLD"
 }

Template:
  {{lowercase 'HELLO WORLD'}}
  {{lowercase var.ucase}}

Results:
 hello world

Date Functions

Below are a few functions to return date within the expression in the desired format.

1. dateFormat

 This function is used to return the input date in a readable format based on the input data specific to your requirements.

Data:
 "var": {
 "date": "2018-04-06"
 }

Template:
{{dateFormat "2018-04-06"}}
{{dateFormat var.date}}

Results:
Apr 6, 2018

Another Example

Data:
 "var": {
 "date": "2018-04-06"
 }

Template:
{{dateFormat "2018-04-06" "YYYY"}}
{{dateFormat var.date "YYYY"}}

Results:
2018

2. dateSet

 This function is used to set the specified type’s value on the date.

 Data:
"var": {
 "date": "2018-04-06"
 }

Template:
{{dateFormat (dateSet "2018-04-06" "date" 8)}}
{{dateFormat (dateSet var.date "date" 8)}}

Results:
Apr 8, 2018

3. dateGet

This function is used to get the specified type’s value on the date.

 Data:
 "var": {
  "date": "2018-04-06"
  }

Template:
 {{dateGet "2018-04-06" "date"}}
 {{dateGet var.date "date"}}

Results:
6

Loop with Condition

Sometimes you have to write a loop with a condition to execute a specific task. The following example shows you how to write a loop with a condition.

Data:
"var": {
 "fruits": [
 {
 "name": "Apple",
 "price": "120"
 },
 {
 "name": "Orange",
 "price": "80"
 },
 {
 "name": "Banana",
 "price": "40"
  },
  {
  "name": "Grapes",
  "price": "50
  }
 ]
 }

Template:
  {{#each  var.fruits}}
  {{name}} {{price}}{{#if  price '>=' 80 }} --Expensive{{/if}}. 
  {{/each}}

Results:
 Apple 120 --Expensive. 
 Orange 80 --Expensive. 
 Banana 40. 
 Grapes 50. 

Double Loop

There are cases where we need to write one loop after another. The following example shows how to write a double loop.

Data:
  "var": {
  "fruits": [
          {  "name": "Apple", "price": "120" },{ "name": "Orange","price": "80" },
          { "name": "Banana", "price": "40" },{ "name": "Grapes","price": "50" } 
           ],
  "veggies": [
           { "name": "Tomato","price": "20" },{ "name": "Pepper","price": "10" },
           { "name": "Beans","price": "30" },{ "name": "Cucumber","price": "35" }
            ]
          }

Template:
 Fruits.
  {{#each  var.fruits}}
  {{name}} {{price}} 
  {{/each}}
 Vegetables.
  {{#each  var.veggies}}
  {{name}} {{price}} 
  {{/each}}

Results:
 Fruits.
  Apple 120 
  Orange 80 
  Banana 40 
  Grapes 50 
 Vegetables.
  Tomato 20 
  Pepper 10 
  Beans 30 
  Cucumber 35

Scoping Change

Scope determines the visibility of variables and other resources in areas of your code. Scoping Change is used to access a resource without using its entire path to access it. In the given example we have a variable named scope with a key value pair name : Nils. We normally access this value using {{var.scope.name}}. Using scoping change we can access that data by simply using the key (name).

Data:
"var": {
"scope": {
"name": "Nils"
    }
        }

Template:
{{#with var.scope}}{{#if name '==' 'Nils'}} Success{{else}}Failure{{/if}}{{/with}}

Results:
Success

Geospatial Functions

Geospatial functions are used to handle geospatial data in your code. You can find the Geospatial functions in the Geospatial section under Functions in the Data tree. The following are some of the Geospatial functions and their examples.

  1. getZipcode

This function is used to get metadata associated with a zipcode.

Data:
"var": {
 "rows": [
         {
         "area_land": 30759134,
         "area_land_sqmi": 11.876,
         "area_water": 4211475,
         "area_water_sqmi": 1.626,
         "center_lat": 39.61601,
         "center_lng": -105.069449
         }
         ],
   "zip": 80123
       }  

Template:
{{#with (getZipcode var.zip)}}{{area_land}}{{/with}}

Results: 
30759134

Turf Functions

Turf is a JavaScript library for spatial analysis. It includes traditional spatial operations and helper functions for creating GeoJSON data, as well as data classification and statistics tools.

Below are a few Turf Functions

1. bearing

Takes two points and finds the geographic bearing between them, i.e. the angle measured in degrees from the north line (0 degrees) and the output is provided as number  in decimal degrees, between -180 and 180 degrees (positive clockwise)

Inputs

 "var": {
    "p1": [
      -75.343, 39.984
    ],
    "p2": [
      -75.534, 39.123
    ]
  }

Template

{{bearing var.p1 var.p2}}

Output

-170.2330491349224

2. distance

 It is used to calculate the distance between two points in degrees, radians, miles, or kilometers. The result is returned in numbers. The arguments contain a From (point) A To (point) B with options (optional). The default value for the option is ‘kilometers’.

Inputs

"var": {
    "point1": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [ -75.343, 39.984 ]
      }
    },
    "point2": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [ -75.534, 39.123 ]
      }
    }
}

Template

{{distance  var.point1 var.point2}}

Output

97.12922118967835

Another Example

Inputs

"var": {
    "point1": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [ -75.343, 39.984 ]
      }
    },
    "point2": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [ -75.534, 39.123 ]
      }
    },
  "opt": {
      "units": "miles"
    }
  }

Template

{{distance  var.point1 var.point2 var.opt}}

Output

60.35329997171415

            3. bbox

Takes a set of features, calculates the bbox of all input features, and returns a bounding box. The output is returned as bbox extent in minX, minY, maxX, maxY order.

Inputs

"var": {
    "pt": {
      "type": "Feature",
      "properties": {
        "name": "poly1"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [125,-15],
            [113,-22],
            [154,-27],
            [144,-15],
            [125,-15]
          ]
        ]
      }
    }
  }
  
Template

{{bbox var.pt}}

Output

113,-27,154,-15

Array Functions

The JavaScript Array class is a global object that is used in the construction of arrays, which are high-level, list-like objects. JavaScript arrays are not guaranteed to be dense, this depends on how the programmer chooses to use them.

Here’s a list of a few Array Functions

  1.  indexOf

This function iterates over each element of the array and returns the index of the first matching element. The arguments are array (the array to inspect), value (the value to search for) and [fromIndex=0] (the index to search from). If fromIndex is negative, it’s used as the offset from the end of array.

Inputs


"var":{
"fruits": ["apple","banana","cherry","dates"]
}



Template

{{indexOf var.fruits 'dates'}}

Output

3

2. nth

This function is used to get the nth element of an array. If n (number) is negative, the nth element from the end is returned.

Inputs


"var":{
"fruits": ["apple","banana","cherry","dates"]
}



Template

{{nth var.fruits 1}}

Output

banana



Another Example

Inputs


"var": {
    "array": [{"id": 1, "name": "Nick"},{"id": 2, "name": "Sam"},{"id": 3, "name": "Ann"}]
  }



Template

{{ jsonStringify (nth var.array 1) }}

Output

{"id":2,"name":"Sam"}

3.  pullAt

This function is used to remove elements from an array corresponding to indexes and return an array of removed elements.

Inputs

"var":{
"fruits": ["apple","banana","cherry","dates"]
}



Template

{{pullAt var.fruits 2 3}}

Output
		
cherry,dates
							

4. concat

This function is used to create a new array by concatenating an array with another array or values. 

Inputs

var:{
"fruits1": [
      "apple",
      "banana"
    ],
    "fruits2": [
      "cherry",
      "dates"
    ]
}



Template
			
{{concat var.fruits1 var.fruits2}}



Output

apple,banana,cherry,dates

5. compact

This function is used to create an array with all the falsey values removed. The values false, null, 0, “”, undefined, and NaN are falsey. 

While concatenating two arrays, there is a chance for null values getting added to the array. Using compact we can remove those and make the array free of falsey values.

Inputs

	"var":{
"fruits": ["","apple","banana","cherry",null,"dates"]
}



Template


{{compact var.fruits}}


Output

apple,banana,cherry,dates

6. uniq

This function is used to create a duplicate-free version of an array, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array.

Inputs

	"var":{
"fruits": ["apple","banana","cherry","banana","dates"]
}



Template


{{uniq var.fruits}}

Output

apple,banana,cherry,dates
Was this article helpful?
Dislike 0
Previous: Testing
Next: Components Glossary