Skip to content

Commit e44b5e7

Browse files
author
Matej Lednicky
authored
feat(NOJIRA-123): Add onStarted callback for "submission start" event (#627)
1 parent 308715e commit e44b5e7

File tree

10 files changed

+69
-2
lines changed

10 files changed

+69
-2
lines changed

docs/callbacks.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ You can listen to various events as the respondent is filling out the typeform o
1111
Available callbacks:
1212

1313
- **onReady** fires when the form is loaded
14+
- **onStarted** fires on the form "submission start" event
1415
- **onSubmit** fires when user submits the form
1516
- **onClose** fires when user closes the modal window
1617
- **onQuestionChanged** fires when user navigates between form questions
@@ -50,6 +51,36 @@ Or in HTML:
5051
</script>
5152
```
5253

54+
## onStarted
55+
56+
The `onStarted` callback will execute when the embedded typeform "submission start" even is trigerred.
57+
58+
In JavaScript:
59+
60+
```javascript
61+
import { createWidget } from '@typeform/embed'
62+
import '@typeform/embed/build/css/widget.css'
63+
64+
createWidget('<form-id>', {
65+
onStarted: ({ formId, responseId }) => {
66+
console.log(`Form ${formId} started with response ID ${responseId}`)
67+
},
68+
})
69+
```
70+
71+
Or in HTML:
72+
73+
```html
74+
<div data-tf-widget="<form-id>" data-tf-on-started="started"></div>
75+
<script src="//embed.typeform.com/next/embed.js"></script>
76+
<script>
77+
// this function needs to be available on global scope (window)
78+
function started({ formId }) {
79+
console.log(`Form ${formId} started with response ID ${responseId}`)
80+
}
81+
</script>
82+
```
83+
5384
## onSubmit
5485

5586
The `onSubmit` callback will execute immediately after a respondent successfully submits the typeform by clicking the "Submit" button.

docs/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ If you embed via HTML, you need to pass optinos as attributes with `data-tf-` pr
5959
| notificationDays | number | display red notification dot, hide for given number of days since popover is open (popover only) | `undefined` |
6060
| autoClose | number / boolean | time (ms) until the embedded typeform will automatically close after a respondent clicks the Submit button. (all embeds except widget) | `undefined` |
6161
| onReady | function | fires when the form is loaded | `undefined` |
62+
| onStarted | function | fires on the "submission start" event, contains `responseId` in the payload | `undefined` |
6263
| onSubmit | function | fires when user submits the form | `undefined` |
6364
| onClose | function | fires when the form is closed (when opened in modal window) | `undefined` |
6465
| onQuestionChanged | function | fires when user navigates between form questions | `undefined` |

packages/demo-html/public/callbacks.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
data-tf-widget="HLjqXS5W"
1919
data-tf-source="localhost"
2020
data-tf-on-ready="onTypeformReady"
21+
data-tf-on-started="onTypeformStarted"
2122
data-tf-on-submit="onTypeformSubmit"
2223
data-tf-on-question-changed="onTypeformQuestionChanged"
2324
data-tf-on-height-changed="onTypeformHeightChanged"
@@ -28,6 +29,7 @@
2829
data-tf-popup="HLjqXS5W"
2930
data-tf-source="localhost"
3031
data-tf-on-ready="onTypeformReady"
32+
data-tf-on-started="onTypeformStarted"
3133
data-tf-on-submit="onTypeformSubmit"
3234
data-tf-on-question-changed="onTypeformQuestionChanged"
3335
data-tf-on-close="onTypeformClose"
@@ -45,18 +47,21 @@
4547
console.log('form ready', data)
4648
}
4749

50+
function onTypeformStarted(data) {
51+
alert('onStarted')
52+
console.log('form started', data)
53+
}
54+
4855
function onTypeformSubmit(data) {
4956
alert('onSubmit')
5057
console.log('form submitted', data)
5158
}
5259

5360
function onTypeformQuestionChanged(data) {
54-
alert(`onQuestionChanged: ${data.ref}`)
5561
console.log('form question changed', data)
5662
}
5763

5864
function onTypeformHeightChanged(data) {
59-
alert(`onHeightChanged: ${data.height}px`)
6065
console.log('form height changed', data)
6166
}
6267

packages/embed/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Closing and opening a typeform in modal window will restart the progress from th
152152
| [notificationDays](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/popover-html) | number | display red notification dot, hide for given number of days since popover is open (popover only) | `undefined` |
153153
| [autoClose](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/autoclose) | number / boolean | time (ms) until the embedded typeform will automatically close after a respondent clicks the Submit button. (all embeds except widget) | `undefined` |
154154
| [onReady](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/callbacks) | function | fires when the form is loaded | `undefined` |
155+
| [onStarted](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/callbacks) | function | fires on the "submission start" event, contains `responseId` in the payload | `undefined` |
155156
| [onSubmit](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/callbacks) | function | fires when user submits the form | `undefined` |
156157
| [onClose](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/callbacks) | function | fires when the form is closed (when opened in modal window) | `undefined` |
157158
| [onQuestionChanged](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/callbacks) | function | fires when user navigates between form questions | `undefined` |
@@ -228,6 +229,9 @@ You can listen to form events by providing callback methods:
228229
onReady: ({ formId }) => {
229230
console.log(`Form ${formId} is ready`)
230231
},
232+
onStarted: ({ formId, responseId }) => {
233+
console.log(`Form ${formId} started with response ID ${responseId}`)
234+
},
231235
onQuestionChanged: ({ formId, ref }) => {
232236
console.log(`Question in form ${formId} changed to ${ref}`)
233237
},
@@ -259,6 +263,9 @@ Callback method receive payload object from the form. Each payload contains form
259263

260264
- onReady
261265
- `formId` (string)
266+
- onStarted
267+
- `formId` (string)
268+
- `responseId` (string)
262269
- onQuestionChanged
263270
- `formId` (string)
264271
- `ref` (string) identifies currently displayed question

packages/embed/src/base/actionable-options.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export type ActionableOptions = {
1919
* Callback function that will be executed once the typeform is ready.
2020
*/
2121
onReady?: (event: WithFormId) => void
22+
/**
23+
* Callback function that will be executed once the typeform "submission start" event is fired.
24+
*/
25+
onStarted?: (event: WithFormId & WithResponseId) => void
2226
/**
2327
* Callback function that will be executed right after the typeform is successfully submitted.
2428
* @param {Object} event - Event payload.

packages/embed/src/initializers/build-options-from-attributes.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('build-options-from-attributes', () => {
1313
data-tf-disable-tracking
1414
data-tf-disable-auto-focus
1515
data-tf-on-ready="onTypeformReady"
16+
data-tf-on-started="onTypeformStarted"
1617
data-tf-on-submit="onTypeformSubmit"
1718
data-tf-on-question-changed="onTypeformQuestionChanged"
1819
data-tf-on-height-changed="onTypeformHeightChanged"
@@ -37,6 +38,7 @@ describe('build-options-from-attributes', () => {
3738
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3839
const win = window as any
3940
win.onTypeformReady = jest.fn()
41+
win.onTypeformStarted = jest.fn()
4042
win.onTypeformSubmit = jest.fn()
4143
win.onTypeformQuestionChanged = jest.fn()
4244
win.onTypeformHeightChanged = jest.fn()
@@ -53,6 +55,7 @@ describe('build-options-from-attributes', () => {
5355
opacity: 50,
5456
disableTracking: true,
5557
onReady: win.onTypeformReady,
58+
onStarted: win.onTypeformStarted,
5659
onSubmit: win.onTypeformSubmit,
5760
onQuestionChanged: win.onTypeformQuestionChanged,
5861
onHeightChanged: win.onTypeformHeightChanged,

packages/embed/src/initializers/build-options-from-attributes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const buildOptionsFromAttributes = (element: HTMLElement) => {
1313
opacity: 'integer',
1414
disableTracking: 'boolean',
1515
onReady: 'function',
16+
onStarted: 'function',
1617
onSubmit: 'function',
1718
onQuestionChanged: 'function',
1819
onHeightChanged: 'function',

packages/embed/src/utils/create-iframe/create-iframe.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe('create-iframe', () => {
1515
const triggerIframeRedrawMock = jest.spyOn(require('./trigger-iframe-redraw'), 'triggerIframeRedraw')
1616
const options = {
1717
onReady: jest.fn(),
18+
onStarted: jest.fn(),
1819
onSubmit: jest.fn(),
1920
onQuestionChanged: jest.fn(),
2021
onHeightChanged: jest.fn(),
@@ -84,6 +85,13 @@ describe('create-iframe', () => {
8485
expect(options.onReady).toBeCalled()
8586
})
8687

88+
it('should call form-started handler', async () => {
89+
window.postMessage({ type: 'form-started', embedId: 'random-id' }, '*')
90+
await new Promise((resolve) => setTimeout(resolve))
91+
92+
expect(options.onStarted).toBeCalled()
93+
})
94+
8795
it('should call form-screen-changed handler', async () => {
8896
window.postMessage({ type: 'form-screen-changed', embedId: 'random-id' }, '*')
8997
await new Promise((resolve) => setTimeout(resolve))

packages/embed/src/utils/create-iframe/create-iframe.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
getFormHeightChangedHandler,
1111
getFormThemeHandler,
1212
getThankYouScreenButtonClickHandler,
13+
getFormStartedHandler,
1314
} from './get-form-event-handler'
1415
import { triggerIframeRedraw } from './trigger-iframe-redraw'
1516
import { dispatchCustomKeyEventFromIframe } from './setup-custom-keyboard-close'
@@ -28,6 +29,7 @@ export const createIframe = (type: EmbedType, { formId, domain, options }: Creat
2829
const {
2930
iframeProps = {},
3031
onReady,
32+
onStarted,
3133
onQuestionChanged,
3234
onHeightChanged,
3335
onSubmit,
@@ -57,6 +59,7 @@ export const createIframe = (type: EmbedType, { formId, domain, options }: Creat
5759
}
5860

5961
window.addEventListener('message', getFormReadyHandler(embedId, onReady))
62+
window.addEventListener('message', getFormStartedHandler(embedId, onStarted))
6063
window.addEventListener('message', getFormQuestionChangedHandler(embedId, onQuestionChanged))
6164
window.addEventListener('message', getFormHeightChangedHandler(embedId, onHeightChanged))
6265
window.addEventListener('message', getFormSubmitHandler(embedId, onSubmit))

packages/embed/src/utils/create-iframe/get-form-event-handler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ export const getFormReadyHandler = (embedId: string, callback?: callbackFn) => {
55
return getFormEventHandler('form-ready', embedId, callback)
66
}
77

8+
export const getFormStartedHandler = (embedId: string, callback?: callbackFn) => {
9+
return getFormEventHandler('form-started', embedId, callback)
10+
}
11+
812
export const getFormQuestionChangedHandler = (embedId: string, callback?: callbackFn) => {
913
return getFormEventHandler('form-screen-changed', embedId, callback)
1014
}

0 commit comments

Comments
 (0)