Refactor collector section

parent 504f2714
Pipeline #40926058 passed with stage
in 1 minute and 40 seconds
......@@ -22,11 +22,21 @@ webmaster_verifications:
collections_dir: sections
collections:
- quickstart
- guide_editor
- guide_collector
- guide_blocks
- examples
quickstart:
permalink: /
name: Quickstart
guide_editor:
permalink: /guide/editor/
name: Guide - Editor
guide_collector:
permalink: /guide/collector/
name: Guide - Collector
guide_blocks:
permalink: /guide/blocks/
name: Guide - Blocks
examples:
permalink: /examples/
name: Examples
plugins:
- jekyll-sitemap
......
<svg width="118.9" height="56" version="1.1" viewBox="0 0 31.459 14.817" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#fc6d26;}.cls-2{fill:#e24329;}.cls-3{fill:#fca326;}</style></defs><g transform="translate(0 -282.18)"><rect y="282.18" width="29.871" height="14.817" rx="2.1167" ry="2.1167" fill="#2c3e50"/><g fill="#ffffff" letter-spacing="0px" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" aria-label="LIVE DEMO"><text x="15.279688" y="288.34827" fill-opacity=".94118" font-family="Roboto" font-size="3.175px" font-weight="300" stroke-width=".070004" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="15.279688" y="288.34827" fill="#ffffff" fill-opacity=".94118" font-family="Roboto" font-size="3.175px" font-weight="300" stroke-width=".070004" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal">get the</tspan></text><text x="15.244344" y="293.2084" font-family="sans-serif" font-size="9.3776px" stroke-width=".23444" style="line-height:1.25" xml:space="preserve"><tspan x="15.244344" y="293.2084" fill="#ffffff" font-family="Roboto" font-size="4.2199px" font-weight="500" stroke-width=".23444" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal">CODE</tspan></text></g><g transform="matrix(.023513 0 0 .023513 1.0178 283.42)"><path class="cls-1" d="m461.17 301.83-18.91-58.12-37.42-115.28a6.47 6.47 0 0 0-12.27 0l-37.42 115.21h-124.33l-37.42-115.21a6.46 6.46 0 0 0-12.26 0l-37.36 115.21-18.91 58.19a12.88 12.88 0 0 0 4.66 14.39l163.47 118.78 163.44-118.78a12.9 12.9 0 0 0 4.73-14.39" fill="#fc6d26"/><path class="cls-2" d="m293 434.91 62.16-191.28h-124.29z" fill="#e24329"/><path class="cls-1" d="m293 434.91-62.18-191.28h-87z" fill="#fc6d26"/><path class="cls-3" d="m143.75 243.69-18.91 58.12a12.88 12.88 0 0 0 4.66 14.39l163.5 118.8z" fill="#fca326"/><path class="cls-2" d="m143.78 243.69h87.11l-37.49-115.2a6.47 6.47 0 0 0-12.27 0z" fill="#e24329"/><path class="cls-1" d="m293 434.91 62.16-191.28h87.14z" fill="#fc6d26"/><path class="cls-3" d="m442.24 243.69 18.91 58.12a12.85 12.85 0 0 1-4.66 14.39l-163.49 118.71 149.2-191.22z" fill="#fca326"/><path class="cls-2" d="m442.28 243.69h-87.1l37.42-115.2a6.46 6.46 0 0 1 12.26 0z" fill="#e24329"/></g></g></svg>
---
source: sections/_guide_collector/00-introduction.md
title: Collector
code: |
``` bash
# Add the Tripetto collector to your project
$ npm i tripetto-collector
```
---
[![npm](https://img.shields.io/npm/v/{{ site.npm_packages.collector }}.svg?style=flat-square)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
[![license](https://img.shields.io/npm/l/{{ site.npm_packages.collector }}.svg?style=flat-square)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
[![downloads](https://img.shields.io/npm/dt/{{ site.npm_packages.collector }}.svg?style=flat-square)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/tripetto){:target="_blank"}
### Making your forms fly
You use the supplementary collector library to handily deploy smart forms in websites and applications. It turns a [form definition](editor/#definitions) (created with the [editor](../editor/)) into an executable program; a finite state machine that handles all the complex logic and response collection during the execution of the form. Apply any UI framework you like. Or pick from the out-of-the-box implementations for [React](https://gitlab.com/{{ site.accounts.gitlab }}/examples/react){:target="_blank"}, [Angular](https://gitlab.com/{{ site.accounts.gitlab }}/examples/angular){:target="_blank"}, [Material-UI](https://gitlab.com/{{ site.accounts.gitlab }}/examples/react-material-ui){:target="_blank"}, [Bootstrap](https://gitlab.com/{{ site.accounts.gitlab }}/examples/bootstrap){:target="_blank"}, [plain JS](https://gitlab.com/{{ site.accounts.gitlab }}/examples/plain){:target="_blank"} and [more](https://gitlab.com/{{ site.accounts.gitlab }}/examples){:target="_blank"}.
**The collector solves a couple of things at once:**
- #### Form parsing
Firstly, the collector takes on the task of parsing the [form definition](../editor/#definitions) from the editor into an executable program. This altogether eliminates the typically complex programming and editing by hand of logic and flows within forms. Once implemented, the collector will autonomously run whatever you create or alter in the editor.
- #### UI freedom
Also, you can implement your own UI and let the collector do the heavy lifting of running the forms. We don’t impose any particular UI framework or library. You decide how it looks. Just wire it up to any UI you like by using the standard DOM-methods of the browser, or by using a library like [React](https://facebook.github.io/react/){:target="_blank"} or framework like [Angular](https://angular.io/){:target="_blank"}.
You may even go commando and make something completely different. For instance, something like an interface to a braille device, optimizing the experience for visually impaired users.
[![Try the demo](../images/demo-spaced.svg)](https://codepen.io/tripetto/project/full/AbbmLR/){:target="_blank"}
[![View the code](../images/codepen-spaced.svg)](https://codepen.io/tripetto/project/editor/AbbmLR){:target="_blank"}
[![View the package](../images/npm.svg)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
For the implementation of the collector we recommend using [TypeScript](https://www.typescriptlang.org/){:target="_blank"}. The collector package includes typings to enable optimal [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense){:target="_blank"} support.
{: .info }
This step-by-step guide for implementing the collector assumes a good understanding of [TypeScript](https://www.typescriptlang.org/){:target="_blank"}, [object-oriented programming](https://www.typescriptlang.org/docs/handbook/classes.html){:target="_blank"} and [webpack](https://webpack.js.org/){:target="_blank"}.
{: .warning }
---
source: sections/_guide_collector/00-introduction.md
title: Collector
code: |
``` bash
# Add the Tripetto collector to your project
$ npm i tripetto-collector
```
---
[![npm](https://img.shields.io/npm/v/{{ site.npm_packages.collector }}.svg?style=flat-square)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
[![license](https://img.shields.io/npm/l/{{ site.npm_packages.collector }}.svg?style=flat-square)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
[![downloads](https://img.shields.io/npm/dt/{{ site.npm_packages.collector }}.svg?style=flat-square)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/tripetto){:target="_blank"}
### Making your forms fly
You use the supplementary collector library to handily deploy smart forms in websites and applications. It turns a [form definition](editor/#definitions) (created with the [editor](../editor/)) into an executable program; a finite state machine that handles all the complex logic and response collection during the execution of the form. Apply any UI framework you like. Or pick from the out-of-the-box implementations for [React](https://gitlab.com/{{ site.accounts.gitlab }}/examples/react){:target="_blank"}, [Angular](https://gitlab.com/{{ site.accounts.gitlab }}/examples/angular){:target="_blank"}, [Material-UI](https://gitlab.com/{{ site.accounts.gitlab }}/examples/react-material-ui){:target="_blank"}, [Angular Material](https://gitlab.com/{{ site.accounts.gitlab }}/examples/angular-material){:target="_blank"} and [more](https://gitlab.com/{{ site.accounts.gitlab }}/examples){:target="_blank"}.
**The collector solves a couple of things at once:**
- #### Form parsing
Firstly, the collector takes on the task of parsing the [form definition](../editor/#definitions) from the editor into an executable program. This altogether eliminates the typically complex programming and editing by hand of logic and flows within forms. Once implemented, the collector will autonomously run whatever you create or alter in the editor.
- #### UI freedom
Also, you can implement your own UI and let the collector do the heavy lifting of running the forms. We don’t impose any particular UI framework or library. You decide how it looks. Just wire it up to any UI you like by using the standard DOM-methods of the browser, or by using a library like [React](https://facebook.github.io/react/){:target="_blank"} or framework like [Angular](https://angular.io/){:target="_blank"}.
You may even go commando and make something completely different. For instance, something like an interface to a braille device, optimizing the experience for visually impaired users.
[![Try the demo](../../images/demo-spaced.svg)](https://example-react-conversational.tripetto.com/){:target="_blank"}
[![Get the code](../../images/code.svg)](https://gitlab.com/{{ site.accounts.gitlab }}/examples/react-conversational){:target="_blank"}
[![Get the package](../../images/npm.svg)](https://www.npmjs.com/package/{{ site.npm_packages.collector }}){:target="_blank"}
For the implementation of the collector we recommend using [TypeScript](https://www.typescriptlang.org/){:target="_blank"}. The collector package includes typings to enable optimal [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense){:target="_blank"} support.
{: .info }
This step-by-step guide for implementing the collector assumes a good understanding of [TypeScript](https://www.typescriptlang.org/){:target="_blank"}, [object-oriented programming](https://www.typescriptlang.org/docs/handbook/classes.html){:target="_blank"} and [webpack](https://webpack.js.org/){:target="_blank"}.
{: .warning }
---
source: sections/_guide_collector/01-concepts.md
bookmark: concepts
name: Concepts
title: Concepts
---
The collector handles the start-to-finish process of flowing the respondent through the smart form, typically based on **conditions** met along the way. It does so by presenting the [form definition](../editor/#definitions), which consists of **nodes**, **clusters** and **branches**, one appropriate step at a time during a so-called **instance**. Without us imposing any particular UI. And at the end of this process the supplied user data is returned and you can take it from there.
The collector acts as a finite state machine that handles all the complex logic during the execution of the form. This state machine also emits events to any UI you choose to apply to the form. And because it holds its own state, it has some interesting features like pausing and resuming sessions (instances). And even switching devices.
Also, the collector inherently supports multi-paged forms, even though it is still a purely client-side library. This does require a somewhat different approach for the rendering of the forms. But that particular approach comes with complete UI freedom for you and greatly enhanced form responsiveness because, contrary to traditional form handling, no server round trips are needed once the instance is initiated.
![Collector diagram](../images/diagrams/collector.svg)
**FYI**, we tend to call the forms you build with Tripetto *smart* because they can contain this advanced logic and conditional flows, allowing for jumps from one part of the form to another or the skipping of certain parts altogether; all depending on the respondent's input.
{: .info }
#### Overview
The following structural diagram shows the aforementioned entities and their respective relationships in a typical basic arrangement. Important to understand is that each cluster in a branch can in turn have branches originating from that cluster. So the following basic structure can recursively repeat itself.
![Form structure](../images/diagrams/structure.svg)
#### Entities
Before we dive into the implementation of the collector itself we need to define these entities:
#### `Nodes`
A form consists of form elements. These will typically be the form input controls, such as a text input control, dropdown control, etc. In Tripetto we call those elements *nodes*.
#### `Clusters`
One or more *nodes* can be placed in so-called *cluster*. Generally speaking a cluster will render as a page or view. Based on the form logic defined with the editor certain clusters are displayed or just skipped.
#### `Branches`
One or more *clusters* can form a *branch*. A branch can be conditional, meaning it will only be displayed in certain circumstances.
#### `Conditions`
A *branch* can contain one or more *conditions*, which are used to direct flow into the pertaining branch. They are evaluated when a cluster ends. Only subsequent branches with matching condition(s) will be displayed.
#### `Instances`
When a a valid [form definition](../editor/#definitions) is provided to the collector a so-called *instance* can be started. An instance represents a single input/user session. As long as the form is not completed, the related instance remains active. When an instance is started, the first cluster with nodes is automatically displayed. And when eventually there are no more clusters to display, the form is considered complete. The instance is then ended, an appropriate event emitted and the collected form input data provided.
**BTW**, instances can also be paused and resumed later on. In a typical UI-oriented application only one instance at a time can be active. More complex use cases are conceivable, but out of scope of this documentation for now.
{: .info }
#### `Slots`
Data collected with a collector needs to be stored somewhere. Tripetto works with a slot system where each data component is stored in a separate [slot](../blocks/#slots). The slots are defined in the form definition and are directly accessible inside the collector.
---
source: sections/_guide_collector/01-concepts.md
bookmark: concepts
name: Concepts
title: Concepts
---
The collector handles the start-to-finish process of flowing the respondent through the smart form, typically based on **conditions** met along the way. It does so by presenting the [form definition](../editor/#definitions), which consists of **nodes**, **clusters** and **branches**, one appropriate step at a time during a so-called **instance**. Without us imposing any particular UI. And at the end of this process the supplied user data is returned and you can take it from there.
The collector acts as a finite state machine that handles all the complex logic during the execution of the form. This state machine also emits events to any UI you choose to apply to the form. And because it holds its own state, it has some interesting features like pausing and resuming sessions (instances). And even switching devices.
Also, the collector inherently supports multi-paged forms, even though it is still a purely client-side library. This does require a somewhat different approach for the rendering of the forms. But that particular approach comes with complete UI freedom for you and greatly enhanced form responsiveness because, contrary to traditional form handling, no server round trips are needed once the instance is initiated.
![Collector diagram](../../images/diagrams/collector.svg)
**FYI**, we tend to call the forms you build with Tripetto *smart* because they can contain this advanced logic and conditional flows, allowing for jumps from one part of the form to another or the skipping of certain parts altogether; all depending on the respondent's input.
{: .info }
#### Overview
The following structural diagram shows the aforementioned entities and their respective relationships in a typical basic arrangement. Important to understand is that each cluster in a branch can in turn have branches originating from that cluster. So the following basic structure can recursively repeat itself.
![Form structure](../../images/diagrams/structure.svg)
#### Entities
Before we dive into the implementation of the collector itself we need to define these entities:
#### `Nodes`
A form consists of form elements. These will typically be the form input controls, such as a text input control, dropdown control, etc. In Tripetto we call those elements *nodes*.
#### `Clusters`
One or more *nodes* can be placed in so-called *cluster*. Generally speaking a cluster will render as a page or view. Based on the form logic defined with the editor certain clusters are displayed or just skipped.
#### `Branches`
One or more *clusters* can form a *branch*. A branch can be conditional, meaning it will only be displayed in certain circumstances.
#### `Conditions`
A *branch* can contain one or more *conditions*, which are used to direct flow into the pertaining branch. They are evaluated when a cluster ends. Only subsequent branches with matching condition(s) will be displayed.
#### `Instances`
When a a valid [form definition](../editor/#definitions) is provided to the collector a so-called *instance* can be started. An instance represents a single input/user session. As long as the form is not completed, the related instance remains active. When an instance is started, the first cluster with nodes is automatically displayed. And when eventually there are no more clusters to display, the form is considered complete. The instance is then ended, an appropriate event emitted and the collected form input data provided.
**BTW**, instances can also be paused and resumed later on. In a typical UI-oriented application only one instance at a time can be active. More complex use cases are conceivable, but out of scope of this documentation for now.
{: .info }
#### `Slots`
Data collected with a collector needs to be stored somewhere. Tripetto works with a slot system where each data component is stored in a separate [slot](../blocks/#slots). The slots are defined in the form definition and are directly accessible inside the collector.
---
source: sections/_guide_collector/02-preparation.md
bookmark: preparation
title: Preparation
---
To use the collector library in your project you should install the collector package as a dependency using the following command:
```bash
$ npm install {{ site.npm_packages.collector }} --save
```
It contains the library runtime files as well as the TypeScript declaration files (typings). When you import a symbol from the library, TypeScript should be able to automatically find the appropriate type definition for you.
#### Setting up your IDE and building your application
We suggest to use [webpack](https://webpack.js.org/){:target="_blank"} for building your website or application. It can bundle the collector runtime with your project. Take a look at one of our [examples](#examples) to see how to configure webpack for this. If you use [webpack](https://webpack.js.org/){:target="_blank"} to bundle your application, you probably want to install the library package as `devDependencies` using `--save-dev` instead of `--save`.
This documentation is updated as we continue our work on Tripetto and build a community. Please [let us know](../support) if you run into issues or need additional information. We’re more than happy to keep you going and also improve the documentation.
{: .warning }
---
source: sections/_guide_collector/02-preparation.md
bookmark: preparation
title: Preparation
---
To use the collector library in your project you should install the collector package as a dependency using the following command:
```bash
$ npm install {{ site.npm_packages.collector }} --save
```
It contains the library runtime files as well as the TypeScript declaration files (typings). When you import a symbol from the library, TypeScript should be able to automatically find the appropriate type definition for you.
#### Setting up your IDE and building your application
We suggest to use [webpack](https://webpack.js.org/){:target="_blank"} for building your website or application. It can bundle the collector runtime with your project. Take a look at one of our [examples](#examples) to see how to configure webpack for this. If you use [webpack](https://webpack.js.org/){:target="_blank"} to bundle your application, you probably want to install the library package as `devDependencies` using `--save-dev` instead of `--save`.
This documentation is updated as we continue our work on Tripetto and build a community. Please [let us know](../../support) if you run into issues or need additional information. We’re more than happy to keep you going and also improve the documentation.
{: .warning }
......@@ -4,84 +4,6 @@ bookmark: nodes
name: Nodes
title: Implementing nodes
sub: true
code: |
``` typescript
import * as React from "react";
import { NodeBlock, INodeBlock, node, Instance, Await } from "tripetto-collector";
interface IExample extends INodeBlock {
Name: string;
}
@node("example")
export class Example extends NodeBlock<JSX.Element, IExample> {
public OnRender(instance: Instance): JSX.Element {
const slot = this.SlotAssert("value");
const data = this.DataAssert<string>(instance, slot);
return (
<label title={this.Node.Props.Explanation}>
{this.Node.Props.Name && this.Node.Props.NameVisible && this.Node.Props.Name}
{this.Node.Props.Description && <p>{this.Node.Props.Description}</p>}
<input
type="text"
required={slot.Required}
defaultValue={data.Value}
placeholder={this.Node.Props.Placeholder}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => (data.Value = e.target.value)}
onBlur={(e: React.FocusEvent<HTMLInputElement>) => ((e.target as HTMLInputElement).value = data.Value)}
/>
</label>
);
}
public OnValidate(
instance: Instance): boolean {
const slot = this.SlotAssert("value");
const value = this.DataAssert<string>(instance, slot);
return !slot.Required || value.Value !== "";
}
}
```
{: title="React" }
``` typescript
import { NodeBlock, INodeBlock, node, Instance, Await } from "tripetto-collector";
interface IExample extends INodeBlock {
Name: string;
}
@node("example")
export class Example extends NodeBlock<HTMLElement, IExample> {
public OnRender(instance: Instance): void {
const data = this.DataAssert<string>(instance, "value");
const label = document.createElement("label");
const input = document.createElement("input");
input.value = data.Value;
input.setAttribute("type", "text");
input.addEventListener("change", () => (data.Value = input.value));
label.textContent = this.Props.Name;
label.appendChild(input);
return label;
}
public OnValidate(
instance: Instance): boolean {
const slot = this.SlotAssert("value");
const data = this.DataAssert<string>(instance, slot);
return !slot.Required || data.Value !== "";
}
}
```
{: title="Plain JS" }
---
Now that we have a basic implementation of the collector to handle the rendering of clusters and nodes, we can dive deeper into the specific types of nodes that we want our collector to handle. These node types effectively take care of the implementation of controls in forms, such as text inputs, dropdowns, checkboxes, and the like. But they are not limited to solely visuals controls. They could also encompass a calculation or other 'invisible' behavior in the form.
......@@ -90,111 +12,27 @@ Node types in Tripetto are called blocks. Block packages can be created by [anyo
That's the editor-part of the story. But how does the collector then know how to render those blocks for your website or application? Well, it doesn't. That's why you need to explicitly implement the blocks you want to support in your collector.
To make this implementation of node blocks as easy as possible, the collector library contains a base class `NodeBlock`. This class requires two methods: An `OnRender` method, which renders the block, and an `OnValidate` method, which allows you to validate your block. The basic implementation of a node block looks like this:
To make this implementation of node blocks as easy as possible, the collector library contains a base class `NodeBlock`. The basic implementation of a node block looks like this:
```typescript
import { NodeBlock, node, Instance, Await, Callback } from "{{ site.npm_packages.collector }}";
@node("your-block-name")
export class YourBlock extends NodeBlock<Rendering, Properties> {
public OnRender(
instance: Instance,
action: Await): Rendering {
// Invoked when the block should return or do its rendering
}
public OnValidate(
instance: Instance,
current: "unknown" | "fail" | "pass",
callback: Callback<boolean>): boolean | Callback<boolean> {
// Invoked when the block should be validated
}
}
```
The `NodeBlock<Rendering, Properties>` class takes two type parameters:
- `Rendering`: This is the return type of the render method (set it to `void` if your render function does not return anything);
- `Properties`: This is an interface that describes the available properties of the block. Most block packages for the editor expose an interface with the properties it implements. This interface can be used here to preserve duplicate interface declaration.
### Decorators, properties and methods
##### **node**(*id*)
{: .decorator }
{: .required }
This decorator specifies the identifier of your block and it should exactly match the identifier of the [block implementation](../blocks/#nodes) for the editor.
`id`
: Specifies a unique identifier for the block.
##### **OnRender**(*instance*, *action*): *rendering*
{: .method }
{: .required }
{: .event }
Invoked when the block should be rendered.
`instance`
: Reference to the instance.
`action`
: Use this parameter to notify the collector the node block is ready by invoking `action.Done()`. It requests the next step in the execution of the form.
##### **OnValidate**(*instance*, *current*, *callback*)
{: .method }
{: .required }
{: .event }
Invoked when the block should be validated.
`instance`
: Reference to the instance.
`current`
: Contains the previous validation state of the block. Can be one of the following values:
- `unknown`: Previous validation unknown;
- `fail`: Previous validation failed;
- `pass`: Previous validation passed.
`callback`
: If you want to perform an asynchronous validation, you should use this object as a return value for the validation function. When your validation is done, you should invoke `callback.Done()`.
Validation examples:
```typescript
// Synchronous example
public OnValidate(): boolean {
// Retrieves data from a certain slot
const slot = this.SlotAssert("example");
const data = this.DataAssert<string>(instance, slot);
return !slot.Required || data.Value !== "";
}
// Asynchronous example
public OnValidate(
instance: Instance,
current: "unknown" | "fail" | "pass",
callback: Callback<boolean>): Callback<boolean> {
// Let's take some time to do this validation
setTimeout(() => {
// Retrieves data from a certain slot
const slot = this.SlotAssert("example");
const data = this.DataAssert<string>(instance, slot);
// Set the payload of the callback
callback.Payload = !slot.Required || data.Value !== "";
}, 1000);
return callback;
}
import { NodeBlock, block } from "{{ site.npm_packages.collector }}";
@block({
type: "node",
identifier: "your-block-name"
})
export class YourBlock extends NodeBlock<{
// Props here
}> {}
```
### Properties
Within your node block class you can access the properties of the block, which are stored in the form definition, through the `Props` member. The type of this data structure is determined by the supplied `Properties` type in the class definition of your block. Your properties interface needs to extend `INodeBlock`.
Within your node block class you can access the properties of the block, which are stored in the form definition, through the `props` member. The type of this data structure is determined by the supplied `Properties` type in the class definition of your block.
### Working with slots
The actual data gathered by the collector is stored in slots. The available slots in the collector are determined by the editor block implementation (you can read more about that [here](../blocks/#slots)). Inside the collector you can use the method `this.Data<T>(...)` or `this.DataAssert<T>(...)` within your `NodeBlock` derived class to retrieve the data of a certain slot. In the code sample to the right (or below if you’re reading this on a small screen) you can see how this works. The `DataAssert` function will throw an error if the requested slot/data is not found. It's return value is always a valid data slot. The `Data` function on the other hand does not throw an error in case of an invalid slot/data. In that case it returns `undefined`. If you want to retrieve the slot itself (this contains the slot metadata) you can use `this.Slot(...)` or `this.SlotAssert(...)`.
The actual data gathered by the collector is stored in slots. The available slots in the collector are determined by the editor block implementation (you can read more about that [here](../blocks/#slots)). Inside the collector you can use the method `this.valueOf(...)` within your `NodeBlock` derived class to retrieve the data of a certain slot.
### Static nodes
Static nodes are used to display static text in the form. These nodes don't have a block attached to it. So the `Block` property of such nodes is `undefined`. The `OnInstanceRender` of your collector class is a good place to verify whether a node has a block. If so, the block should be rendered. If not, you can render the node `Name` and optional `Description` to your UI.
Static nodes are used to display static text in the form. These nodes don't have a block attached to it. So the `block` property of such nodes is `undefined`.
This documentation is updated as we continue our work on Tripetto and build a community. Please [let us know](../support) if you run into issues or need additional information. We’re more than happy to keep you going and also improve the documentation.
{: .warning }
---
source: sections/_guide_collector/03.02-conditions.md
bookmark: conditions
name: Conditions
title: Implementing conditions
sub: true
code: |
``` typescript
import { ConditionBlock, IConditionBlock, condition, Instance } from "tripetto-collector";
interface IExample extends IConditionBlock {
Match: string;
}
@condition("example")
export class Example extends ConditionBlock<IExample> {
public OnCondition(instance: Instance): boolean {
const data = this.DataAssert<string>(instance);
return data.String === this.Props.Match ? true : false;
}
}
```
---
Conditions are used to direct flow in a form. They don't render to a UI. But they do need an implementation in your collector. A typical condition takes a value from a certain slot and evaluates it against an expectation.
To make the implementation of condition blocks as easy as possible, the collector library contains a base class `ConditionBlock`. This class requires a single method `OnCondition`, which performs the conditional evaluation. The basic implementation of a condition block looks like this:
```typescript
import { ConditionBlock, condition, Instance, Callback } from "{{ site.npm_packages.collector }}";
@condition("your-block-name")
export class YourBlock extends ConditionBlock<Properties> {
public OnCondition(
instance: Instance,
callback: Callback<boolean>): boolean | Callback<boolean> {
// Invoked when the condition should be evaluated
}
}
```
The `ConditionBlock<Properties>` class takes one type parameter:
- `Properties`: This is an interface that describes the available properties of the block. Most block packages for the editor expose an interface with the properties it implements. This interface can be used here to preserve duplicate interface declaration.
### Decorators, properties and methods
##### **condition**(*id*)
{: .decorator }
{: .required }
This decorator specifies the identifier of your block and it should exactly match the identifier of the [block implementation](../blocks/#conditions) for the editor.
`id`
: Specifies a unique identifier for the block.
##### **OnCondition**(*instance*, *callback*)
{: .method }
{: .required }
{: .event }
Invoked when the condition should be evaluated.
`instance`
: Reference to the instance.
`callback`
: If you want to perform an asynchronous evaluation, you should use this object as a return value for the condition function. When your evaluation is done, you should feed the result to `callback.Payload`.
Examples:
```typescript
// Synchronous example
public OnCondition(): boolean {
// Retrieves data for the attached slot
const data = this.DataAssert<string>(instance);
// If the data is not empty, the condition is `true`
return data.Value !== "" ? true : false;
}
// Asynchronous example
public OnCondition(
instance: Instance,
callback: Callback<boolean>): Callback<boolean> {
// Let's take some time to do this evaluation
setTimeout(() => {
// Retrieves data for the attached slot
const data = this.DataAssert<string>(instance);
// We're done and always ok :-)
callback.Payload = data.Value !== "" ? true : false;
}, 1000);
return callback;
}
```
### Properties
Within your condition block class you can access the properties of the block, which are stored in the form definition, through the `Props` member. The type of this data structure is determined by the supplied `Properties` type in the class definition of your block. Your properties interface needs to extend `IConditionBlock`.
### Working with slots
The actual data gathered by the collector is stored in slots. The available slots in the collector are determined by the editor block implementation (you can read more about that [here](../blocks/#slots)). Inside the collector you can use the method `this.Data(...)` within your `ConditionBlock` derived class to retrieve a certain slot and evaluate its data value. In the code sample to the right (or below if you’re reading this on a small screen) you can see how this works.
This documentation is updated as we continue our work on Tripetto and build a community. Please [let us know](../support) if you run into issues or need additional information. We’re more than happy to keep you going and also improve the documentation.
{: .warning }
---
source: sections/_guide_collector/03.02-conditions.md
bookmark: conditions
name: Conditions
title: Implementing conditions
sub: true
---
Conditions are used to direct flow in a form. They don't render to a UI. But they do need an implementation in your collector. A typical condition takes a value from a certain slot and evaluates it against an expectation.
To make the implementation of condition blocks as easy as possible, the collector library contains a base class `ConditionBlock`. The basic implementation of a condition block looks like this:
```typescript
import { ConditionBlock, block, condition } from "{{ site.npm_packages.collector }}";
@Tripetto.block({
type: "condition",
identifier: "your-block-name"
})
export class YourBlock extends ConditionBlock<{
// Props here
}> {
@condition
verifyCondition(): boolean {
return true;
}
}
```
### Properties
Within your condition block class you can access the properties of the block, which are stored in the form definition, through the `props` member. The type of this data structure is determined by the supplied `Properties` type in the class definition of your block.
### Working with slots
The actual data gathered by the collector is stored in slots. The available slots in the collector are determined by the editor block implementation (you can read more about that [here](../blocks/#slots)). Inside the collector you can use the method `this.valueOf(...)` within your `ConditionBlock` derived class to retrieve a certain slot and evaluate its data value.
This documentation is updated as we continue our work on Tripetto and build a community. Please [let us know](../support) if you run into issues or need additional information. We’re more than happy to keep you going and also improve the documentation.
{: .warning }
---
source: sections/_guide_collector/03.03-instances.md
bookmark: instances
name: Instances
title: Using instances
sub: true
code: |
``` typescript
// This example assumes the form definition is loaded to `definition`
const collector = new ExampleDOMCollector(definition);
// Start the collector
const instance = collector.Start();
```
---
To start a collector session you need to load a [form definition](../editor/#definitions) and start an instance. The actual loading of the form definition is something you should implement yourself (e.g. by using an HTTP GET). In the following examples we assume there is a form definition stored in the variable `definition`.
```typescript
// Creates a collector with the supplied form definition
const collector = new Collector(definition);
// Start a new instance
const instance = collector.Start();
```
The instance contains the actual session data. The collector supports instances to run simultaneously, but in a typical UI implementation you can only start one instance at a time (this is the default behavior).
If your form definition includes blocks that are not implemented in your collector and thus unavailable, the form definition cannot be loaded. The construction of the collector will throw an error.
{: .error }
#### Stopping the collector
To stop the collector, invoke the `Stop` function. This will kill the active instance(s).
```typescript
// Assuming there is a collector instance with name `collector`
collector.Stop();
```
#### Pausing the collector
It is possible to pause all instances of a collector using the `Pause` function. All the state data necessary to restore the collector later on is saved to a special data structure called a *snapshot*. You can save the snapshot data en feed it back to the collector to resume it.