# Form Validation and Analytics
# Form validation, analytics and form submission JS handling in Vue apps & in other scripts
- Create a callback function, it must be a named function. This function will be called once the form passes validation. To prevent normal form submission the function must always return
false.eventis never passed through, so we can't callevent.preventDefault()and expect the form not to submit naturally. - Make sure that your form doesn't have any other submit handlers and submit button doesn't have any on-click events that deal with submission logic, all logic must happen in a function defined in step 1.
- Enable validation on a form & pass through the callback function that will be called when the form validates.
# Vue.js example
Example of a form that submits a call to API, with an HTML version of API parameters added as a fallback.
Form code
<form class="form--forgot luminateApi" name="lLogonForm" method="post" action="{{ apiPath }}CRConsAPI" v-if="isSendUsernamePwSubmitted === false">
<p>Please enter the email address associated with this account.</p>
<div class="form__row">
<label for="form__email" class="form__label"><span class="form__required">*</span>Email Address</label>
<input class="form__input" type="email" name="email" id="form__email" v-model="email" required="required" maxlength="60" />
</div>
<div class="form__row">
<button class="button--teal">Continue</button>
<input type="hidden" name="api_key" value="{{apiKey}}" />
<input type="hidden" name="method" value="login" />
<input type="hidden" name="v" value="1.0" />
<input type="hidden" name="success_redirect" value="{{nextUrl}}" />
</div>
</form>
Custom method within a Vue.js component for handling the submission
sendUsernamePw: function ($form) {
var myVue = this;
luminateExtend.api({
api: 'cons',
callback: function (data) { myVue.sendUsernamePwCallback(data); },
data: 'method=login&email=' + encodeURIComponent(this.email) + '&send_user_name=true',
useHTTPS: true
});
myVue.isSendUsernamePwSubmitted = true;
return false;
},
Vue.js component ready method that invoked form validation and analytics with a callback function
ready: function () {
enableFormValidation('.form--forgot', 'html5', this.sendUsernamePw);
}
# JavaScript example
Survey submission example, a bit more involved but it is likely to be used throughout.
Form code
<form class="form form--newsletter-sign-up" id="form--newsletter-sign-up" name="newsletter-sign-up" method="post" action="https://support.savethechildren.org/site/SSurvey">
<div class="form__row form__row--colums">
<div class="form__column">
<label for="form__email" class="form__label"><span class="form__required">*</span>Email Address</label>
<input class="form__input" type="email" name="cons_email" id="form__email" required="required" maxlength="60" />
</div>
<div class="form__column">
<label for="4368_1441_2_1301" class="form__label"><a href="#mobile-opt-in-language" class="form__label-link" data-s-object-id="Text|†|"><sup>†</sup></a>Mobile Number</label>
<input type="tel" name="4368_1441_2_1301" id="4368_1441_2_1301" class="form__input" pattern="[(][0-9]{3}[)] [0-9]{3}-[0-9]{4}" placeholder="(555) 555-5555" data-validation="custom">
</div>
<div class="form__column">
<button class="button--teal">Continue</button>
<input type="hidden" name="ACTION_SUBMIT_SURVEY_RESPONSE" id="ACTION_SUBMIT_SURVEY_RESPONSE" value="Submit Survey" />
<input type="hidden" name="cons_info_component" id="cons_info_component" value="t" />
<input type="hidden" name="SURVEY_ID" id="SURVEY_ID" value="1441" />
</div>
</div>
</form>
Form submission callback function which handles survey submission to Luminate
surveySubmitHandler($form) {
var email = $form.find('input[name="cons_email"]').val();
var formData = $form.find(':input:not(:hidden)').serialize();
var formSource = 'NEWSLETTER';
var sourceCode = $form.find('input[name="source"]').val();
var subSourceCode = $form.find('input[name="sub_source"]').val();
var surveyId = $form.find('input[name="SURVEY_ID"]').val();
// prep form for API submission
formData = 'survey_id=' + surveyId + '&' + formData;
// Add source codes to the form data
if (typeof sourceCode !== 'undefined') {
formData += '&source=' + sourceCode;
}
if (typeof subSourceCode !== 'undefined') {
formData += '&sub_source=' + subSourceCode;
}
// Remove any previous errors, set by the API
$form.find('.form__error').remove();
// Submit the value to Cheetah mail as well, use existing function
submitPixelToCheetahMail(formSource, email);
// We'll use existing Luminate API library for simplicity
luminateExtend.api.request({
'api': 'survey',
'data': 'method=submitSurvey&' + formData,
'callback': function (data) {
if (typeof data.errorResponse === 'undefined'){
$form.addClass('js-hidden');
console.debug('form has submitted successfully, hiding it');
}
},
'requiresAuth': true,
'useHTTPS': true
});
}
Code execution on page load that enables form validation and analytics with a submit callback
$(document).ready(function () {
enableFormValidation('.form--newsletter-sign-up', 'html5', surveySubmitHandler);
});
# Form analytics without validation on AEM or Luminate pages
Form code and function code surveySubmitHandler are the same as in the previous example.
Attach each analytics event individually
$(document).ready(function () {
var $form = $('.form--newsletter-sign-up');
if ($form.length > 0) {
// Set form into data layer
setAnalyticsForm($form);
// Enable form abandonment
formAbandonmentAnalytics($form);
// Set marketing source codes
$form.setMarketingSourceCodes();
// Update the last touched field
$form.on('change', 'input', function (event) {
var $form = $(event.currentTarget);
// if page has more than one form on it, update the form in the data layer to the last touched one
setAnalyticsForm($form);
// update the last touched input
setFormLastField($form);
});
// Attach an on submit event, here calling a function defined in a previous example
$form.on('submit', function (event) {
var $form = $(event.currentTarget);
surveySubmitHandler($form);
});
// Not handling errors are we expect the browser to properly validate input.
// Server error handling can be handled in the callback function to luminateApi call.
}
});
# Form analytics on third-party scripts inserted on AEM page
In this example we use Opt-in Monster scripts
/**
* Helper function for recording responses in LUminate
* @param {JSON Object} data Response provided by Opt-in Monster
*/
function recordResponsesInLuminate(data) {
var email = ''; // TODO get value from response
var firstName = ''; // TODO get value from response
var lastName = ''; // TODO get value from response
var surveyId = '1441'; // TODO update to any value
var surveyFormData = 'surevey_id=' + surveyId;
if (typeof email !== 'undefined' && email !== '') {
surveyFormData += '&cons_email=' + email
+ '&cons_first_name=' + email
+ '&cons_last_name=' + email;
}
// We'll use existing Luminate API library for simplicity
luminateExtend.api.request({
'api': 'survey',
'data': 'method=submitSurvey&' + surveyFormData,
'callback': function (data) {
if (typeof data.errorResponse === 'undefined'){
console.debug('form has submitted successfully');
}
},
'requiresAuth': true,
'useHTTPS': true
});
}
/**
* Helper function for recording responses in Cheetah mail
* @param {JSON Object} data Response provided by Opt-in Monster
*/
function recordResponsesInCheetahMail(data) {
var email = ''; // TODO get value from response
var firstName = ''; // TODO get value from response
var lastName = ''; // TODO get value from response
// This function is defined in global scripts
submitPixelToCheetahMail(formSource, email, firstName, lastName);
}
// Attach listener events
document.addEventListener('om.Campaigns.init', function(event) {
var campaigns = event.detail.Campaigns;
var formId = '';
var formName = '';
if (campaigns.length > 0) {
// TODO set form variables to valid values
setFormAnalyticsData(formId, formName);
}
});
document.addEventListener('om.Campaign.close', function(event) {
var campaign = event.detail.Campaign;
var formId = '';
var formName = '';
var lastTouchedField = '';
// TODO: update test for validity
if (campaign.length > 0) {
// TODO set form variables to valid values
setFormAbandonment(formId, formName, lastTouchedField);
}
});
document.addEventListener('om.Optin.success', function(event) {
var data = event.detail.response;
var campaigns = event.detail.Campaign;
var formId = '';
var formName = '';
var lastTouchedField = '';
// TODO: update test for validity
if (typeof data !== 'undefined') {
// TODO set form variables to valid values
setFormSubmission(formId, formName, lastFieldName);
// TODO update as needed
recordResponsesInLuminate(data);
// TODO update as needed
recordResponsesInCheetahMail(data);
}
});
document.addEventListener('om.Optin.error', function(event) {
var errorMessage = event.detail.response;
var errorType = 'sign up error'
var formId = '';
var formName = '';
var lastTouchedField = '';
if (typeof errorMessage !== 'undefined' && errorMessage !== '') {
// TODO set form variables to valid values
setFormError(formId, formName, lastFieldName, errorMessage, errorType);
}
});
# Additional Validation Options
You can find all available validation option on the validation library site. https://github.com/victorjonsson/jQuery-Form-Validator