Skip to content

Commit fef6b50

Browse files
Paul Boocockgreg-el
authored andcommitted
Allow enableFormTracking to capture dynamic form changes (close #748)
1 parent dbd8762 commit fef6b50

File tree

5 files changed

+101
-27
lines changed

5 files changed

+101
-27
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@snowplow/browser-plugin-form-tracking",
5+
"comment": "Allow enableFormTracking to capture dynamic form changes (#748)",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@snowplow/browser-plugin-form-tracking"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@snowplow/javascript-tracker",
5+
"comment": "Allow enableFormTracking to capture dynamic form changes (#748)",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@snowplow/javascript-tracker"
10+
}

plugins/browser-plugin-form-tracking/src/helpers.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export type transformFn = (x: string | null, elt: ElementData | TrackedHTMLEleme
7575

7676
export const innerElementTags: Array<keyof TrackedHTMLElementTagNameMap> = ['textarea', 'input', 'select'];
7777

78+
type TrackedHTMLElementWithMarker = TrackedHTMLElement & Record<string, boolean>;
79+
7880
const defaultTransformFn: transformFn = (x) => x;
7981

8082
interface FormConfiguration {
@@ -92,34 +94,38 @@ export function addFormListeners(tracker: BrowserTracker, configuration: FormTra
9294
trackingMarker = tracker.id + 'form',
9395
config = getConfigurationForOptions(options);
9496

95-
Array.prototype.slice.call(document.getElementsByTagName('form')).forEach(function (form) {
96-
if (config.formFilter(form) && !form[trackingMarker]) {
97-
Array.prototype.slice.call(innerElementTags).forEach(function (tagname) {
98-
Array.prototype.slice.call(form.getElementsByTagName(tagname)).forEach(function (innerElement) {
99-
if (
100-
config.fieldFilter(innerElement) &&
101-
!(innerElement as any)[trackingMarker] &&
102-
innerElement.type.toLowerCase() !== 'password'
103-
) {
104-
addEventListener(
105-
innerElement,
106-
'focus',
107-
getFormChangeListener(tracker, config, 'focus_form', context),
108-
false
109-
);
110-
addEventListener(
111-
innerElement,
112-
'change',
113-
getFormChangeListener(tracker, config, 'change_form', context),
114-
false
115-
);
116-
(innerElement as any)[trackingMarker] = true;
117-
}
118-
});
97+
Array.prototype.slice.call(document.getElementsByTagName('form')).forEach(function (form: HTMLFormElement) {
98+
if (config.formFilter(form)) {
99+
Array.prototype.slice.call(innerElementTags).forEach(function (tagname: keyof TrackedHTMLElementTagNameMap) {
100+
Array.prototype.slice
101+
.call(form.getElementsByTagName(tagname))
102+
.forEach(function (innerElement: TrackedHTMLElementWithMarker) {
103+
if (
104+
config.fieldFilter(innerElement) &&
105+
!innerElement[trackingMarker] &&
106+
innerElement.type.toLowerCase() !== 'password'
107+
) {
108+
addEventListener(
109+
innerElement,
110+
'focus',
111+
getFormChangeListener(tracker, config, 'focus_form', context),
112+
false
113+
);
114+
addEventListener(
115+
innerElement,
116+
'change',
117+
getFormChangeListener(tracker, config, 'change_form', context),
118+
false
119+
);
120+
innerElement[trackingMarker] = true;
121+
}
122+
});
119123
});
120124

121-
addEventListener(form, 'submit', getFormSubmissionListener(tracker, config, trackingMarker, context));
122-
form[trackingMarker] = true;
125+
if (!form[trackingMarker]) {
126+
addEventListener(form, 'submit', getFormSubmissionListener(tracker, config, trackingMarker, context));
127+
form[trackingMarker] = true;
128+
}
123129
}
124130
});
125131
}

trackers/javascript-tracker/test/integration/autoTracking.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const isMatchWithCallback = F.isMatchWith((lt, rt) => (F.isFunction(rt) ? rt(lt)
3939
const SAFARI_EXPECTED_FIRST_NAME = 'Alex';
4040
const SAFARI_EXPECTED_MESSAGE = 'Changed message';
4141

42+
declare var addField: () => void;
43+
4244
describe('Auto tracking', () => {
4345
if (F.isMatch({ browserName: 'internet explorer', version: '9' }, browser.capabilities)) {
4446
fit('Skip IE9', () => {}); // Automated tests for IE autotracking features
@@ -296,6 +298,14 @@ describe('Auto tracking', () => {
296298

297299
browser.pause(1000);
298300

301+
browser.execute(() => {
302+
addField();
303+
});
304+
305+
$('#newfield').click();
306+
307+
browser.pause(1000);
308+
299309
loadUrlAndWait('/form-tracking.html?filter=exclude');
300310

301311
$('#fname').click();
@@ -331,6 +341,30 @@ describe('Auto tracking', () => {
331341
);
332342
});
333343

344+
it('should send focus_form for the dynamically added form element', () => {
345+
expect(
346+
logContains({
347+
event: {
348+
event: 'unstruct',
349+
app_id: 'autotracking',
350+
unstruct_event: {
351+
data: {
352+
schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0',
353+
data: {
354+
formId: 'myForm',
355+
elementId: 'newfield',
356+
nodeName: 'INPUT',
357+
elementType: 'text',
358+
elementClasses: [],
359+
value: 'new',
360+
},
361+
},
362+
},
363+
},
364+
})
365+
).toBe(true);
366+
});
367+
334368
it('should send focus_form and change_form on text input', () => {
335369
// Safari 12.1 doesn't fire onchange events when clearing
336370
// However some browsers don't support setValue

trackers/javascript-tracker/test/pages/form-tracking.html

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,28 @@
1414
return query;
1515
}
1616
</script>
17+
<script type="text/javascript">
18+
function addField() {
19+
var fields = document.getElementById('fields');
20+
fields.appendChild(document.createTextNode('New Field: '));
21+
var input = document.createElement('input');
22+
input.type = 'text';
23+
input.id = 'newfield';
24+
input.name = 'newfield';
25+
input.value = 'new';
26+
fields.appendChild(input);
27+
fields.appendChild(document.createElement('br'));
28+
snowplow('enableFormTracking');
29+
}
30+
</script>
1731
</head>
1832

1933
<body>
2034
<p id="title">Page for Form Tracking testing with Snowplow Micro</p>
2135
<div id="init"></div>
2236

2337
<form id="myForm" class="formy-mcformface" action="/form-tracking.html">
24-
<fieldset>
38+
<fieldset id="fields">
2539
<legend>Personal Info:</legend>
2640
<label for="fname">First name:</label><br />
2741
<input type="text" id="fname" name="fname" value="John" class="test" /><br />

0 commit comments

Comments
 (0)