# Template Parser

## Introduction
This is the main way perform screen generation. Schemas are converted to html presentations.
Note that it only produces html, what you do with that is up to you. 
If your intent is to embed that html in your current screen I reconmend using the dynamic view loader as it will help you manage the data context and bindings.

## What gets generated
If you want to see what get's generated please look at the template parser constants file.

## Usage
`const html = this.templateParser.parse(templateJson)`

## Generate html from schema and inject it into container
```
this.templateParser.parse(JSON.parse(template)).then(result => {
    this.dynamicViewLoader.load(result, this.genContainer, this);
});
```

## Schema
The schema consists out of three parts:
1. type
1. body

Type defines what type of schema it is, it does not affect the generation process.  
Body define the actual layout and properties used in the screen generation process.

Recognised shorthands for screen generation are:

1. tabsheet
1. groups
1. input
1. readonly
1. checkbox
1. memo
1. button
1. elements
1. element
1. card
1. select
1. radio
1. template
1. list
1. details
1. master-detail
1. visualization

## General structure

```js
{
    "type": "",         what type of schema is this -- own use
    "datasets": [],     models that define structure and validation
    "datasource": [],   datasource definitions
    "body": {},         body of schema and what needs to be generated
    "templates": []     templates that are referenced in the body section
}
```

## General properties
You will often see the following properties for schemas in the examples below:
1. styles
1. attributes

Styles is an array of string values that populates the "class" attribute and attributes allow you to add any attribute to the element.
Attributes are defined as a object literal were the key is the name of the attribute and the value, the value of the attribute.
Using attributes you can add any aurelia custom attribute if you like.

e.g.
```json
{
  "element": "ul",
  "elements": [
    {
      "element": "li",
      "attributes": {
        "repeat.for": "item of items"
      },
      "content": "${item.text}"
    }
  ]
}
```

In the above example we are injecting the aurelia term that will affect binding of the list item.
The attribute defined above will translate into the aurelia term `repeat.for="item of items"`. 
Note that the context here is the view model. If your data is on a model object you will need to define that manually as `item of model.items`, the prefix does not apply to custom element schemas.

NOTE: there are a number of properties that are considered required properties and there will be failure on generating the schema when this happens.
Where documented the following fields are required.

1. Field
2. Title
3. Dataset
4. Datasource

## Tabsheet schema item
Tabsheet is a array of tabs.

```json
{
  "element": "tabsheet",
  "elements": [
    {
      "id": "tab1",
      "title": "Tab 1",
      "template": 0
    },
    {
      "id": "tab2",
      "title": "Tab 2",
      "template": 1
    }
  ]
}


Each tab has to define:
1. id - a unique identifier for this tab on the view
2. title - what caption should the tab should have
3. template - template id which references the template object, this will be the tab sheet content


## Groups
The groups container allows you to define 1 to N group objects.

```json
"groups": [
  {
    id: "myGroup",
    title: "My Group",
    elements: [
        ...
    ]
  }
]
```

Using groups like this means that you can only have groups as children.
If you don't want only group children but mix it in with headers you have to use the "elements" objects and set the element type to group

```
"elements":[
    {
        "element": "h2",
        "content": "Hello World"
    },
    {
        "element": "group",
        "id": "detailGroup",
        "title": "detail",
        "elements": [
            ... elements go here
        ]
]
```
Each group item has to define:
1. id - a unique identifier for this group on the view
1. title - what caption should the group should have

## Input
The input schema is a 1:1 match for the html element "input". Input items are rendered in a input composite that manages layout and other features.

```json
{
  "element": "input",
  "title": "Site Code",
  "field": "site_code",
  "description": "code for site",           // optional - can use aurelia binding expression here ${siteCode}
  "styles": ["css-class-1", "css-class-2"], // optional
  "attributes": {                           // optional
    "pattern": "[Aa-Zz]"
  }
}
```
To define different input types, the right way to do that is to use the html5 type attribute.
You can read more about the different types at: https://www.w3schools.com/html/html_form_input_types.asp
Please note that this is not to be used for buttons. If you want to show buttons, please use see the button section.

There is an additional property to be used: `"as-detail": true`. This is often used in scenarios where the context is the model. 
An example of this is templates used in details. In those cases you don't want the default "model." prefix in the property.

If you set "as-detail" true then it strips the "model." prefix from the field bindings. When you are defining input types in templates you want to make sure it is set and is set to true.

## Readonly
The readonly composite in may ways work the same as the input but instead of having a input it now uses a div.
This means people can still select content, but not edit it and this also works for reporting purposes where you just want to display information.

```json
{
    "element": "readonly",
    "title": "Code",
    "field": "model.code",
    "styles": ["depreciated"]
}
```

## Checkbox
The checkbox schea creates a input of type checkbox. It uses a particular composite layout as defined by the pragma standard layout.

```json
{
  "element": "checkbox",
  "title": "Is Active",
  "field": "is_active",
  "styles": ["switch"],                     // optional
  "attributes": {                           // optional
    "pattern": "[Aa-Zz]"
  }
}
```

## Memo
The memo schema translates to a html textarea control. This is also wrapped in a input composite.
If you want to use a textarea without the input composite rather use the "element" schema and define it as a textarea.

```json
{
  "element": "memo",
  "title": "Site Code",
  "field": "site_code",
  "description": "code for site",
  "styles": ["css-class-1", "css-class-2"],
  "attributes": {
    "pattern": "[Aa-Zz]"
  }
}
```

## Button
The button schema translates to a html button element.

```json
{
  "element": "button",
  "title": "Click Me",
  "action": 0,
  "styles": ["css-class-1", "css-class-2"],
  "attributes": {
    "readonly": "true"
  }
}
```

Actions point to the id of a action defined in the schema.
See actions documentation for more details (actions.md)
Please note that the action does not have any brackets as this is used for the binding expression and is automatically added. All you need to provide is the delegate name.

## Element
The element schema allows us to render any html we want. Any tagname can be used to define the content. This includes web components that your project uses.

```json
{
  "element": "div",
  "styles": ["container", "horizontal"],
  "attributes": {
    "role": "aria-toolbar"
  },
  "elements": [
      ...
  ]
}
```

## Card
Card is a shorthand for `<div class="card default-padding"></card>`

```json
{
    "element": "card",
    "elements": [
      ... place content here
    ]
}
```

It is important to note that all children of this element must be defined in the "elements" array. You can build the dom tree with "element" and "elements" pairs.

## Select
Select represents a dropdown box in html 5. 
Select has a field that it binds to. When making a selection that field is updated with the selected item's id.

```json
{
    "element": "select",
    "datasource": 0,
    "title": "Status",
    "field": "status"
}
```

Note the datasource property. This property defines the id of a datasource defined in the datasource section of the schema.
See datasource for more details

## Radio
Radio provides a mechanism to show radio groups. 
Radio is very much the same as select expect that you don't provide a title.


```json
{
    "element": "radio",
    "datasource": 1,
    "field": "option"
}
```

1. for more details on datasource see datasource section below.
1. field is the field the selected value is bound to, same as select.

Because radio groups don't have a title you can build it into your UI as you please, but if you need to have a titled group, the suggested schema layout is as following:

```json
{
    "element": "card",
    "elements": [
        {
            "element": "h3",
            "content": "Option"
        },
        {
            "element": "radio",
            "datasource": 1,
            "field": "option"
        }
    ]
}
```

If you want to use it as a stand along collapseable group you can use group instead of card.  
See groups for more details.

## Datasource
Datasources define a collection of values used when binding to collections.  
Common scenarios for this things like:

1. Select
1. Radio Groups
1. Details
1. Repeatable templates...

### Define items in schema
This is often used when you are hard coding what items you want in the list and is not defined by a external resource

```json
{
  "id": 0,
  "resource": [
      {
          "id": 0,
          "title": "Status 1"
      },
      {
          "id": 1,
          "title": "Status 2"
      },
      {
          "id": 2,
          "title": "Status 3"
      }
  ]
}
```   
Things to note in the above example:

1. id is required and should be a unique id in the datasource collection.
1. resource is an array in this case and defines a set object structure.
1. The object structure defines a id and option property, id for the value used in binding and option for text displayed.

### Property options to use in binding
```json
{
  "id": 1,
  "field": "context.options"
}
```

The above example binds to a options property on the context.
Context is the object that is defined as context on the pragma-views control and is often the view model.

The model structure expected here is the same id / title pair as above.

Id is processed as a string so you can use strings in the id field if you so want.

### Remote
When creating a dataset factory, you can pass a datasource collection callback as part of the constructor.
When populating remote this callback will be called for you to fetch the items to be used.
To make this work you need to define a remote property.

```json
{
  "id": 1,
  "name": "remote key name",
  "remote": "someremotekey"
}
```

When setInitialValues is called on the datasource will be populated, but if you don't want that but only fetch the collection when you request it, you need to define that in the schema.

```json
{
    "id": 3,
    "remote": "details-resource",
    "delay-fetch": true,
    "visualization-data": true
}
```

When defining a datasource for lookups, the delay-fetch and visualization-data properties should be set to true.

## Dataset
The schema allows you to define datasets. These structures are translated into models that you can use for bindinging against.
Please note though that this is not an automatic process but you need to request the models from DatasetFactory.
For more details on the dataset please see the DatasetFactory.

## Template
As can be seen in the general structure the schema allows for templates. Templates are normal UI parts as you would have defined in the body.
Templates are defined by having a id and elements tag.


### Defining a template
```json
{
  "id": 0,
  "elements": [
      {
          "element": "group",
          "title": "Other Options",
          "elements": [
              {
                  "element": "input",
                  "title": "value",
                  "field": "description",
                  "attributes": {
                      "type": "text"
                  }
              }
          ]
      }
  ]
}
```

### Using the template
```json
{
    "element": "template",
    "template": 0
}
```

The template id used here must match the id of a template defined the templates section of the schema.  
You can also define a template being conditional using the condition property.

```json
{
    "element": "template",
    "template": 0,
    "condition": "model.option == 1"
}
```

If you define a condition it will map to the Aurelia if.bind attribute and any Aurelia condition can be used here.
Note that in the case of condition you will need to define the full path.  
If you want to check values on the model then you need to provide that in the binding and if you want to do checks on the context then you need to define that path as `context.property == true`;

## List
List is a shorthand to display a list of selectable items.
The list requries that you pass it a datasource to use and a template.
Datasource can either be the id of a datasource to use or the field path `e.g. "model.collection1"`

```json
{
    "element": "list",
    "datasource": 0,
    "template": 1
}
```

There are additional properties you can define.

1. selection-field: defaults to 'selectedId', set this property if you want to change the selection property name
1. change-model: defaults to true, if you set it to false "model-selector" custom attribute will be excluded from the composite.
1. multi-select: defaults to false, set to true if you want list to enable multi selection. if multi-select is true, change-model will be set to false.

## Details
Details is a control that allows you to display a collection of input items.
This will add a add and delete button at the bottom so that you can add new detail items ore delete existing ones.

```json
{
    "element": "details",
    "datasource": "model.header.contract",
    "template": 1,
    "action": 0
}
```

The datasource property defined where to get the data from and this can either be a id of the datasource of the fieldname path.
Template defines the template id to use to render each item and functions in much the same way as the list does.
If the property you are using is a collection property on the dataset it will create a method for you. This method name should be defined in the action property.
If you want to take charge of this process you can point the action property to your custom function.

## master-detail
The master detail allows you to have a master detail control in your view providing you with two spaces.
The left space is called the master and the right side the detail.
You can really add what ever you want there but commonly you would have a list of some sort in the master and the details you want to look at in the right.

```json
{
    "element": "master-detail",
    "attributes": {
        "is-master-visible": true
    },
    "master": [
        {
            "element": "list",
            "datasource": 1,
            "template": 1,
            "change-model": true,
            "selection-field": "selectedId"
        }
    ],
    "detail": [
        {
            "element": "input",
            "title": "Id",
            "field": "model.id"
        },
        {
            "element": "input",
            "title": "Code",
            "field": "model.code"
        },
        {
            "element": "input",
            "title": "Description",
            "field": "model.description"
        },
        {
            "element": "button",
            "action": 0,
            "title": "Debug"
        }
    ]
}
```

please note the attribute "is-master-visibile", if you don't set this by default the master will not show.

## visualization
Visualization is the display of records that managed a perspective. You can look at the same data from different angles.
If I have list of work orders, I can group it in different ways get look at the data from different angles. You can group by asset to see what the work load on the assets are.
You can group by date to see when the work is mostly being done. 

Visualization allows you to display the information fetched in different ways as you chosen by the user.

```json 
{
    "element": "visualization",
    "datasource": "model.details",
    "type": "grid",
    "perspective": 1
},
{
    "element": "visualization",
    "datasource": "model.details",
    "type": "chart",
    "options": ["bar", "red"],
    "perspective": 2
}
```

Above we have two examples of visualizations. The second has additional options. See the documentation on each visualization to see what options are supported.
Important parts to note here are:

1. What datasource to use to get data for the visualization.
2. What perspective to use for this visualization.

Perspectives define how the data is massaged and can be shared by multiple visualizations.

```json
{
    "id": 1,
    "cache": "details",
    "grouping": [
        {
            "siteCode": "count"
        },
        {
            "locationCode": "min"
        }
    ],
    "sorting": {
        "siteCode": "ascending",
        "locationCode": "ascending"
    }
},
{
    "id": 2,
    "cache": "details",
    "sorting": {
        "siteCode": "ascending",
        "locationCode": "descending"
    }
}
```

Perspectives must have the following properties:

1. Id - to identify the perspective
1. Cache - a identifier used for sotring the data to build different perspectives from.

Multiple perspectives can share the same cache id as long as the data source is the same.
You can then build different perspectives with different groupings from the same data cache.

The real work behind the perspective however has to do with grouping and sorting.
You don't need to define both, but you must define either one or the other.
If you do define groupings you have to also define what aggregate function to use on the grouping.
The aggregate act as summaries on how you want to see the data.

## Variables
There are a number of schenarios when you want to have access to variables on a schema level.
Typical scenarios include:

1. Varialbe labels depending on translation or industry.
2. State variables that don't logically make up part of the data models.

Schema varialbes are defined by creating a variables object at the root level of the schema.

```json
{
    "variables": [
        "labelCode": "Code",
        "selectedId": -1,

        "complexVariable": {
            "label": "Wazaap",
            "value": ""
        }
    ],
    "body": {
        "elements": [
            {
                "element": "input",
                "title": "@labelCode",
                "field": "@selectedId"
            },
            {
                "element": "input",
                "title": "@complexVariable.label",
                "field": "@complexVariable.value"
            }
        ]
    }
}

```

In the above example you can see both how the variables are declared and used.
Important things not note:

1. Variables can be simple or complex objects but not arrays.
2. Refering to a variable you must prefix the use case with "@"

Depending on where you use the variable the binding generated will differ.
For title the binding will be a content binding "${schema.varialbes.labelCode}".
For fields the binding will be property path bindings ...bind(schema.variables.selectedId)

If you have a use case where the "@" prefix does not generate the right binding you require, you can also define the bindings manually through the attributes.
In such cases you will need to define the full path yourself starting with "schema" as the root object found in pragma-form.



