Skip to content

Commit

Permalink
feat(TU-8694): Pass option to prefill first question (#640)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathio committed Feb 23, 2024
1 parent 6e77e3f commit 8dc8924
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 18 deletions.
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ If you embed via HTML, you need to pass optinos as attributes with `data-tf-` pr
| keepSession | boolean | preserve form state when modal window is closed (and re-opened) | `false` |
| redirectTarget | string | target for [typeforms with redirect](https://www.typeform.com/help/a/redirect-on-completion-or-redirect-through-endings-360060589532/), valid values are `_self`, `_top`, `_blank` or `_parent` ([see docs on anchor target](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-target)) | `_parent` |
| disableScroll | boolean | disable navigation between questions via scrolling and swiping | `false` |
| preselect | object | preselect answer to the first question ([more info in help center](https://www.typeform.com/help/a/preselect-answers-through-typeform-links-for-advanced-users-4410202791060/)) | `undefined` |

## Options in plain HTML embed

Expand Down
41 changes: 41 additions & 0 deletions packages/demo-html/public/preselect-html.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Static HTML Demo</title>
<style>
#wrapper {
width: 100%;
max-width: 600px;
height: 400px;
margin: 0 auto;
}
.element {
position: fixed;
bottom: 0;
right: 0;
background: red;
color: white;
padding: 10px;
width: 200px;
height: 60px;
line-height: 40px;
z-index: 10000;
}
</style>
</head>
<body>
<div class="element">I have z-index 10k</div>
<p>This embed preselects the answer to <strong>6</strong> and continues to next question.</p>
<p><a href="https://www.typeform.com/help/a/preselect-answers-through-typeform-links-for-advanced-users-4410202791060/">More info in this help center article.</a></p>
<div
id="wrapper"
data-tf-widget="HLjqXS5W"
data-tf-medium="demo-test"
data-tf-iframe-props="title=Foo Bar"
data-tf-preselect="37ca107f130fef3a=6"
></div>
<script src="./lib/embed.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions packages/embed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ Closing and opening a typeform in modal window will restart the progress from th
| disableScroll | boolean | disable navigation between questions via scrolling and swiping | `false` |
| hubspot | boolean | enable HubSpot source tracking - for details see article [Set up source tracking for HubSpot](https://www.typeform.com/help/a/set-up-source-tracking-for-hub-spot-4413167079316/) | `false` |
| [fullScreen](https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/widget-full-screen-html) | boolean | enable full screen view, set `<body>` size, resize on screen resize - also when browser navbars are displayed on mobile | `false` |
| [preselect] (https://codesandbox.io/s/github/Typeform/embed-demo/tree/main/demo-html/preselect-html) | object | preselect answer to the first question ([more info in help center](https://www.typeform.com/help/a/preselect-answers-through-typeform-links-for-advanced-users-4410202791060/)) | `undefined` |

### Options in plain HTML embed

Expand Down
4 changes: 4 additions & 0 deletions packages/embed/src/base/url-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,8 @@ export type UrlOptions = {
* Do not use H1 tags inside the form
*/
noHeading?: boolean
/**
* Preselect first question (ref) with answer (ref)
*/
preselect?: Record<string, string>
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ export const buildOptionsFromAttributes = (element: HTMLElement) => {
disableScroll: 'boolean',
fullScreen: 'boolean',
noHeading: 'boolean',
preselect: 'record',
})
}
8 changes: 7 additions & 1 deletion packages/embed/src/utils/build-iframe-src.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ describe('build-iframe-src', () => {
hubspot: true,
autoResize: true,
onEndingButtonClick: () => {},
noHeading: true,
preselect: {
question1: 'value2',
},
}
expect(buildIframeSrc({ formId: 'some-id', type: 'widget', embedId: 'embed-id', options })).toBe(
'https://form.typeform.com/to/some-id' +
Expand All @@ -134,9 +138,11 @@ describe('build-iframe-src', () => {
'&typeform-embed-handles-redirect=1' +
'&typeform-embed-auto-resize=true' +
'&typeform-embed-handle-ending-button-click=true' +
'&typeform-embed-no-heading=true' +
'&utm_foo=utm+foo+value&foobar=foobar%26value' +
'#foo=foo+value&bar=%40bar%26value%3F' +
'&hubspot_page_name=page+title&hubspot_page_url=http%3A%2F%2Flocalhost%2F'
'&hubspot_page_name=page+title&hubspot_page_url=http%3A%2F%2Flocalhost%2F' +
'&answers-question1=value2'
)
})

Expand Down
58 changes: 41 additions & 17 deletions packages/embed/src/utils/build-iframe-src.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,46 @@ const getBaseUrl = (formString: string, domain = DEFAULT_DOMAIN): URL => {
return new URL(`https://${domain}/to/${formString}`)
}

const makePreselectParam = (preselect?: Record<string, string>) => {
if (!preselect) {
return null
}
const questionRef = Object.keys(preselect).at(0)
const answerRef = (questionRef && preselect[questionRef]) || undefined

if (questionRef === undefined || answerRef === undefined) {
return null
}
return {
key: `answers-${questionRef}`,
value: answerRef,
}
}

const buildHashParams = (url: URL, options: BaseOptions & UrlOptions): string => {
const hashParams = new URLSearchParams()

if (options.hidden) {
Object.entries(options.hidden)
.filter(([, paramValue]) => isDefined(paramValue) && paramValue !== '')
.forEach(([paramName, paramValue]) => {
// if transitive params is true, make hidden field values take priority over transitive params
if (typeof options.transitiveSearchParams === 'boolean') {
url.searchParams.delete(paramName)
}
hashParams.set(paramName, paramValue)
})
}

const preselectParam = makePreselectParam(options.preselect)
if (preselectParam) {
const { key, value } = preselectParam
hashParams.set(key, value)
}

return hashParams.toString()
}

export const buildIframeSrc = (params: BuildIframeSrcOptions): string => {
const { domain, formId, type, embedId, options } = params
const queryParams = mapOptionsToQueryParams(type, embedId, addDefaultUrlOptions(options))
Expand All @@ -104,23 +144,7 @@ export const buildIframeSrc = (params: BuildIframeSrcOptions): string => {
options.hidden = { ...options.hidden, ...hubspotHiddenFields }
}

if (options.hidden) {
const searchParams = new URLSearchParams()

Object.entries(options.hidden)
.filter(([, paramValue]) => isDefined(paramValue) && paramValue !== '')
.forEach(([paramName, paramValue]) => {
// if transitive params is true, make hidden field values take priority over transitive params
if (typeof options.transitiveSearchParams === 'boolean') {
url.searchParams.delete(paramName)
}
searchParams.set(paramName, paramValue)
})
const hiddenFields = searchParams.toString()
if (hiddenFields) {
url.hash = hiddenFields
}
}
url.hash = buildHashParams(url, options)

return url.href
}
Expand Down

0 comments on commit 8dc8924

Please sign in to comment.