Here’s probably a post hidden in the deep recesses of the web. Will it be helpful to anyone? It was an adventure with ups and downs with a totally different solution in the end, but it was a learning experience. If you’re like me, then this article might even be fun to read.
A client wants to use jotForm to store their form data. It will use SSL to securely transfer the data and they trust their servers to be more secure than some joe schmoe web host platform.
I thought, no problem, let’s just embed the form using an iFrame. And it worked. But soon it was discovered, the iFrame’s height did not update itself properly when the screen width was narrow like on a mobile device. Glancing at the code, they have an event that runs every so many microseconds, computes the height and sets it on the iFrame. It was always too small and it cut off the bottom of the form. SO my idea was to copy the html markup of the form and use my javascript skills to bring it to life and still have the form be submitted to jotForm. I wanted to be able to use the original HTML markup jotForm produced, so it would be easy to do this with other jotForm’s or if we decided to add fields to this form in the future.
This was a multi-step or multi-page form so I needed to create the javascript to do this. I also needed validation of the fields. I also needed to format the data. Many steps….
First I went down the path of making a multi-page form. It wasn’t as bad as I thought. It only took a few lines of javascript code. I had created the form using JotForm and added pagebreaks. JotForm markup puts each page in a <ul class="page-section>
. The markup also already contains the buttons in the last <li>
of each <ul>
Overall, I needed to initialize the form: hiding all pages but the first one, adding a data attribute with the page number so I can target the pages with the Back and Next buttons. Then, I needed to add events on the Next and Back buttons that would show the proper page and hide all the others. Here’s my code:
$('document').ready(function() {
var $form, $formPages;
$form = $('.jotform-form'); //variable pointing to form
$formPages = $form.find('.page-section'); //array of each form page
initializeFormPages($formPages);
$('.form-pagebreak-back').on('click', backButtonEvent);
$('.form-pagebreak-next').on('click', nextButtonEvent);
});
Here’s the functions in detail:
var hidePage = function($page) {
$page.slideUp();
};
var showPage = function($page) {
$page.slideDown();
};
var backButtonEvent = function(e) {
var $this = $(this);
var page = $this.parents('ul').attr('data-page');
page = (typeof page !== 'undefined') ? parseInt(page) : -1;
if( page > 0 ) {
hidePage($this.parents('ul'));
showPage($('[data-page="' + (--page) +'"]'));
}
};
var nextButtonEvent = function(e){
var $this = $(this);
var page = $this.parents('ul').attr('data-page');
page = (typeof page !== 'undefined') ? parseInt(page) : -1;
if($this.parents('form').valid()) { //jQuery Validation..don't go forward unless form is valid
hidePage($this.parents('ul'));
showPage($('[data-page="' + (++page) + '"]'));
}
};
var initializeFormPages = function($formPages) {
var numPages = $formPages.length;
$formPages.each(function(i, page) {
$(page).attr('data-page', i) //add page number to each
.removeAttr('style') //remove existing styles
.css('display','none'); //hide each page
if (i === 0) {
$(page).css('display','block'); //show first page
$(page).find('.form-pagebreak-back-container').css('display','none'); //hide back button on first page
} else if (i === numPages-1 ) {
$(page).find('.form-pagebreak-next-container').css('display','none'); //hide next button on last page
}
});
};
For validation I used jQuery Validation by jzaefferer (see jqueryvalidation.org). It’s relatively easy and fast to configure. Looking at the form code, I determined which fields to validate. $.valid() function is run when the Next button is clicked. This function appears to only validate fields that are visible on the screen which is exactly what is needed for a multi-page form. It will not submit unless all fields are valid.
$('form.jotform-form').validate({
rules: {
'q3_name[first]' : {
required: true,
minlength: 2
},
'q3_name[last]' : {
required: true,
minlength: 2
},
'q29_phoneNumber[area]' : {
required: true,
minlength: 3,
number: true
},
'q4_email' : {
email: true
},
'q29_phoneNumber[phone]' : {
required: true
},
'q15_dateOf15[month]' : {
range: [1, 12]
},
'q15_dateOf15[day]' : {
range: [1, 31]
},
'q15_dateOf15[year]' : {
range: [1900, 2030]
}
},
messages: {
'q3_name[first]' : {
required: "Please input your first name",
minlength: "Please type in your full first name"
},
'q3_name[last]' : {
required: "Please input your last name",
minlength: "Please type in your full last name"
},
'q29_phoneNumber[area]' : {
required: "3 digit area code",
minlength: "3 digit area code",
number: "3 digit area code"
},
'q29_phoneNumber[phone]' : {
required: "Please enter in your 7 digit phone number"
},
'q15_dateOf15[month]' : {
range: "Please enter month: 1 - 12"
},
'q15_dateOf15[day]' : {
range: "Please enter day: 1 - 31"
},
'q15_dateOf15[year]' : {
range: "Please enter a valid 4 digit year"
}
}
});
Lastly, I needed to style it. I could have used the styling code from jotForm. In fact, I probably should have worked with that more to minimize the work I needed. But for whatever reason, I decided to style it myself. It looked like the data-type attribute seemed a bit more static since the id’s and classes all had numbers appended to them. So I used this as the main selector. I also threw in some flex because I think more people should use it. Over 96% of the browsers can use it. And Microsoft is automatically updating, without user consent, those older Windows machines to Windows 10 anyway.
.jotform-form input {
padding: 16px;
}
.jotform-form {
background: #ffffff;
margin: 5px;
padding: 5px 10px 5px 10px;
}
.jotform-form li {
margin-top: 20px;
}
.form-label {
font-weight: 700;
}
.form-sub-label {
font-size: 12px;
}
[data-type="control_text"] {
line-height: 2;
}
[data-type="control_text"] strong {
font-size: 24px;
}
.jotform-form [data-type="control_pagebreak"], .jotform-form [data-type="control_button"]{
text-align: center;
margin-top: 20px;
margin-bottom: 20px;
}
[data-type^="control"] {
display: -ms-flexbox;
display: flex;
-ms-flex-pack: justify;
justify-content: space-between;
}
[data-type^="control"] > label {
display:inline-block;
padding: 16px;
font-size: 16px;
vertical-align: top;
}
[data-type^="control"] > div {
display:inline-block;
-ms-flex-positive: 1;
flex-grow: 1;
}
[data-type="control_pagebreak"] div > div, [data-type="control_button"] div > div {
display: inline-block;
margin: 0 20px;
}
.form-sub-label-container {
display: -ms-inline-flexbox;
display: inline-flex;
-ms-flex-direction: column;
flex-direction: column;
}
[data-type="control_fullname"] .form-sub-label-container {
width: 49%;
}
[data-type="control_phone"] .form-sub-label-container:first-child {
width: 30%;
}
[data-type="control_phone"] .form-sub-label-container:first-child input {
display: inline-block;
width: 75%;
}
.jotform-form .showAutoCalendar, .jotform-form .date-separate, .jotform-form .phone-separate {
display:none;
}
[data-type="control_phone"] .form-sub-label-container:last-child {
width: 60%;
}
li.jf-required {
position: relative;
}
.form-required {
position: absolute;
font-size: 12px;
color: #ff3333;
top: 30%;
left: 0;
}
.form-checkbox-item {
display: block;
}
.form-checkbox-item input{
width: inherit;
}
label.error {
-ms-flex-order: 99;
order: 99; /* need this inline but below the sub container label */
display: -ms-flexbox;
display: flex;
color: #ff3333;
}
input.error {
border: 1px solid #ff3333
}
After doing this, the client decided they wanted to keep their information in their Google Apps using Google Forms. After signing a BAA with Google, Google Forms is considered to be HIPAA-compliant. While JotForms doesn’t have it in writing that they are HIPAA-compliant, they do appear to have the facilities in place to be so. We probably would have stayed with JotForms, but we needed to add encryption to this solution. I’m not talking about SSL here as that is already accomplished. I’m talking about encrypting the form data with a public key before it is sent to JotForm. The data is stored encrypted and the only way anyone could read the data is with a private key stored at the client’s site. This solution removes all of JotForm’s scripts that would do the encrypting.
Google Forms is much more limiting but embedding the form on the website did produce a more mobile capable form than jotForm’s default embed. Google Forms doesn’t have much in validation. I might be able to grab the <form>
action attribute and all the field names to create my own form, but we wanted to get the project done.