Pause and resume
It is possible to pause and resume a form. That allows a respondent to temporarily stop filling in a form and then continue at a later moment. Not only the submitted data is stored, but also the actual state of the runner. That allows the runner to return to the exact state the respondent left it in. The form state is stored in an ISnapshot
object.
There are two ways you can implement pause and resume:
- Use the built-in pause function;
- Use the snapshot function to save the state of a form without pausing it.
When using the built-in pause function, the form terminates when paused (a pause confirmation message is shown to the respondent). So the form needs to be resumed, before the respondent can continue with the form. The snapshot function allows saving the form state, without actually pausing the form.
⏸️ Pause a form
To use the built-in pause function of the runner you need to implement the onPause
event. This enables the pause function in the runner and displays a pause button in the runner UI. There are two options for the pause button:
The second option is useful when you want to retrieve the respondent's email address. For example, you want to send an email message to the respondent with a resume link for the form.
When a form is paused an ISnapshot
object will be created. You need to store this JavaScript object since you need it to resume a session later. When the pause operation succeeds, the form pauses, and a confirmation message is presented to the respondent.
Direct pause
To enable the direct pause feature, use the following code. It enables the pause button in the runner UI. When the respondent clicks the pause button, the state of the runner is stored, and the onPause
event invoked. Use a Promise
to indicate the result of the operation.
- Autoscroll
- Chat
- Classic
import { run } from "@tripetto/runner-autoscroll";
run({
definition: /* Supply your form definition here */,
onPause: (snapshot) =>
new Promise((resolve, reject) => {
// This example uses fetch to post snapshot data to an endpoint
fetch("/example-server", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(snapshot),
})
.then((response) => {
if (response.ok) {
// All good, resolve the promise
resolve();
} else {
// Not so good, reject the promise
reject();
}
})
.catch((error) => {
// Error occurred, reject with error message
reject(error.message);
});
}),
});
import { run } from "@tripetto/runner-chat";
run({
definition: /* Supply your form definition here */,
onPause: (snapshot) =>
new Promise((resolve, reject) => {
// This example uses fetch to post snapshot data to an endpoint
fetch("/example-server", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(snapshot),
})
.then((response) => {
if (response.ok) {
// All good, resolve the promise
resolve();
} else {
// Not so good, reject the promise
reject();
}
})
.catch((error) => {
// Error occurred, reject with error message
reject(error.message);
});
}),
});
import { run } from "@tripetto/runner-classic";
run({
definition: /* Supply your form definition here */,
onPause: (snapshot) =>
new Promise((resolve, reject) => {
// This example uses fetch to post snapshot data to an endpoint
fetch("/example-server", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(snapshot),
})
.then((response) => {
if (response.ok) {
// All good, resolve the promise
resolve();
} else {
// Not so good, reject the promise
reject();
}
})
.catch((error) => {
// Error occurred, reject with error message
reject(error.message);
});
}),
});
Ask for email address and then pause
When you need the respondent's email address to pause the form, use the following code. It asks the respondent for its email address first.
- Autoscroll
- Chat
- Classic
import { run } from "@tripetto/runner-autoscroll";
run({
definition: /* Supply your form definition here */,
onPause: {
recipe: "email",
onPause: (emailAddress, snapshot) =>
new Promise((resolve, reject) => {
// This example uses fetch to post snapshot data to an endpoint
fetch("/example-server", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
emailAddress,
snapshot,
}),
})
.then((response) => {
if (response.ok) {
// All good, resolve the promise
resolve();
} else {
// Not so good, reject the promise
reject();
}
})
.catch((error) => {
// Error occurred, reject with error message
reject(error.message);
});
}),
},
});
import { run } from "@tripetto/runner-chat";
run({
definition: /* Supply your form definition here */,
onPause: {
recipe: "email",
onPause: (emailAddress, snapshot) =>
new Promise((resolve, reject) => {
// This example uses fetch to post snapshot data to an endpoint
fetch("/example-server", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
emailAddress,
snapshot,
}),
})
.then((response) => {
if (response.ok) {
// All good, resolve the promise
resolve();
} else {
// Not so good, reject the promise
reject();
}
})
.catch((error) => {
// Error occurred, reject with error message
reject(error.message);
});
}),
},
});
import { run } from "@tripetto/runner-classic";
run({
definition: /* Supply your form definition here */,
onPause: {
recipe: "email",
onPause: (emailAddress, snapshot) =>
new Promise((resolve, reject) => {
// This example uses fetch to post snapshot data to an endpoint
fetch("/example-server", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
emailAddress,
snapshot,
}),
})
.then((response) => {
if (response.ok) {
// All good, resolve the promise
resolve();
} else {
// Not so good, reject the promise
reject();
}
})
.catch((error) => {
// Error occurred, reject with error message
reject(error.message);
});
}),
},
});
⏯️ Retrieve snapshot without pausing
If you don't want to pause the form but still want to store the state of the form, you can use the form snapshot. This snapshot contains the same data as generated when pausing a form, but in this case, the form remains active.
- Autoscroll
- Chat
- Classic
import { run } from "@tripetto/runner-autoscroll";
// We need a reference to the runner to retrieve the snapshot.
const runner = await run({
definition: /* Supply your form definition here */
});
// Now we can retrieve the snapshot
console.dir(runner.snapshot);
import { run } from "@tripetto/runner-chat";
// We need a reference to the runner to retrieve the snapshot.
const runner = await run({
definition: /* Supply your form definition here */
});
// Now we can retrieve the snapshot
console.dir(runner.snapshot);
import { run } from "@tripetto/runner-classic";
// We need a reference to the runner to retrieve the snapshot.
const runner = await run({
definition: /* Supply your form definition here */
});
// Now we can retrieve the snapshot
console.dir(runner.snapshot);
If you want to keep form sessions persistent in the local storage of the respondent's browser, you can also use the persistent
feature. That feature stores the form snapshot in the local storage of the browser when the respondent leaves the form. When the respondent returns to the form, the session resumes using the snapshot data from the local storage.
▶️ Resume a form
When you have stored the snapshot data, you can resume a form by feeding the snapshot back to the runner.
- Autoscroll
- Chat
- Classic
import { run } from "@tripetto/runner-autoscroll";
run({
definition: /* Supply your form definition here */,
snapshot: /* Supply a form snapshot here */
});
import { run } from "@tripetto/runner-chat";
run({
definition: /* Supply your form definition here */,
snapshot: /* Supply a form snapshot here */
});
import { run } from "@tripetto/runner-classic";
run({
definition: /* Supply your form definition here */,
snapshot: /* Supply a form snapshot here */
});
The structure of the form should not change between pausing (or saving the snapshot) and resuming it. To ensure data consistency, Tripetto compares the fingerprint of the form definition with the fingerprint stored in the snapshot. If there is a mismatch, the form is not resumed, and a new form session is initiated instead.
✅ Validating a snapshot
Using the available JSON Schema for the ISnapshot
data object, you can implement static validation using a JSON Schema validator. You need a validator for the language or framework you are using. For example, if you use Node.js you can use Ajv or Hyperjump to validate the snapshot data.
📥 Download JSON Schema for ISnapshot
There is a list of validators on the JSON Schema website.
Example
The following example shows how to set up validation using the JSON Schema.
- Ajv
- Hyperjump
// Make sure to install ajv first: `npm i ajv`
import Ajv from "ajv";
// Download the schema for the Tripetto Snapshot object and make it available to your code
import tripettoSnapshotSchema from "tripetto-snapshot.schema.json";
const ajv = new Ajv({
validateSchema: false
});
const validate = ajv.compile(tripettoSnapshotSchema);
// Now you can validate the snapshot data
if (validate(/* Supply your snapshot object here */)) {
// All good!
}
// Make sure to install Hyperjump first: `npm i @hyperjump/json-schema`
import JsonSchema from "@hyperjump/json-schema";
// Download the schema for the Tripetto Snapshot object and make it available to your code
import tripettoSnapshotSchema from "tripetto-snapshot.schema.json";
JsonSchema.add(tripettoSnapshotSchema);
const schema = awit JsonSchema.get("https://tripetto.com/sdk/tripetto-snapshot.schema.json");
// Now you can validate the snapshot data
const result = await JsonSchema.validate(
schema,
/* Supply your snapshot object here */
);
if (result.valid) {
// All good!
}
📖 Reference
- Autoscroll
- Chat
- Classic
Have a look at the complete autoscroll runner API reference for detailed documentation. In the examples above, the following symbols were used:
Have a look at the complete chat runner API reference for detailed documentation. In the examples above, the following symbols were used:
Have a look at the complete classic runner API reference for detailed documentation. In the examples above, the following symbols were used: