Formbuilder form in a FancyBox modal view
Previous article Next articleIn this tutorial I will show you how I implemented an Ajax based 'call-me-back' Form Builder form, that pops up in a FancyBox modal view.
What?!
Okay, I might need to explain it first :-)
'Call-me-back' form: a form which a website visitor can use to submit his name and phone number. The website owner will then call the visitor back as soon as possible.
FormBuilder is a very nice module for CMS Made Simple to build and handle forms. I would not know how to create a form in CMSMS without this module.
FancyBox: a Javascript 'tool' to display objects (in this case a webform) on top of the website.
The form also has a very basic and user friendly way of spam(bot) prevention.
The website owner wanted the 'call-me-back' form to be available on every webpage of his website. So on every page there will be a 'call me back!' - button.
How to use
Step 1: Create the webform
Prerequisites - The FormBuilder module needs to be installed and for successful mail handling CMSMailer needs to be properly configured and tested
This form is just an example. Of course you can create other forms to suit your needs.
Extensions >> Form Builder >> 'Add New Form'
Main tab
Form Name: Call me back
Form Alias: call-me-back
Display form inline?: UNchecked (this is very important)
Form Submission tab
After form is submitted: Display "Submission Template"
Submission Template tab
<p>We will call you as soon as possible on number<br />
<strong>{$your_phone_number}</strong></p>
Click the 'Add' button to create the form. Now we need to add some useful fields
- Static Text field (optional):
A field to display some descriptive text above the form. - Text Input:
Name: Your name
Require a response for this Field: checked - Text Input:
Name: Your phone number (this name is referred to from the Submission Template)
Require a response for this Field: checked
Field Validation (optional): I use 'Match regular expression' but it depends on your country/location. - Text Input (we use this field for the spam prevention):
Name: website
Require a response for this Field: NOT(!) checked
Field Validation: Doesn't match Regular Expression
Advanced Settings tab:
Field Alias and DOM id (CSS id) attribute: frm_website
CSS Class for this field: website
Validation Regex: /.+/ - *Email Results to set Address(es):
Name: sendto
"From name" for email: choose an appropriate name for your website
"From address" for email: choose an existing email address for your website domain
Destination Email Address: add the email address of the website owner that needs to receive the webform contents.
Advanced Settings tab:
Create Sample Template (button)
Email Template: remove the stuff for the 'website' field.
Save the form
Test the form by creating a new content page (you might want to hide that from the menu) and add {FormBuilder form='call-me-back'}.
Visit that page and check that it does not validate when anything is filled in 'website' field. Then fill in the other field and leave 'website' empty and check that the Submission template text is displayed and the form is received by the recipient supplied earlier. If tests are successful then you can delete the test-page.
Step 2: Add the form to your page template(s)
For the form to be present on every page I put it in the template. Initially it is hidden with some inline css. We only want to show the form when the 'Call me back!' button is used.
Just before the CLOSING </body> tag I put these lines:
<div id="callme" class="frm_ajax_inner">{FormBuilder form='call-me-back'}</div>
</div>
It is important that the 'container' div has an id that is [id_of_child_div]_container.
So in this example the child div has id="callme" so it's parent has id="callme_container".
If this page template is actually used for some content page and you look at the html source of that webpage (frontend) then you should see the form is there just before the </body> tag.
The css "display: none;" hides it from the visitor.
Step 3: Create a button for showing the form
Somewhere in your page template you want to have a button or link so the website visitor will be able to 'call' the form. I just created a link and with some css made it look like a button. The styling is up to you, I'll just show you the code I used for the link:
Note that the value of href ("#callme") refers to the id of the earlier created div (<div id="callme">). This is how FancyBox later knows what to show when the link is used.
Step 4: Integrate jQuery and FancyBox javascript
FancyBox is based on jQuery, so we first need to link to jQuery.
In the <head> section of your page template put (for example):
Then download the FancyBox files from:
http://fancybox.googlecode.com/files/jquery.fancybox-1.3.4.zip
I use version 1 because version 2 is not free for commercial use. But version 1 is not compatible with jQuery 1.9+. Therefor I needed a patched version which I downloaded from:
http://www.picssel.com/playground/jquery/fancybox/jquery.fancybox-1.3.4_patch.zip
More information on StackOverflow:
http://stackoverflow.com/questions/14344289/fancybox-doesnt-work-with-jquery-v1-9-0-f-browser-is-undefined-cannot-read
I uploaded the original FancyBox files including the patch to the web server:
/uploads/template/js/fancybox
Then I linked to the patched js file; just below the jQuery include put:
Step 5: Some custom javascript to put things together
Now we need to do some stuff:
- make the link/button activate a FancyBox
- make the submit button of the form use Ajax in stead of a normal POST
- make sure the form is available after the FancyBox is closed
I've created a 'prepareForm' function. It finds the form(s) and sets the onSubmit handlers of it so the form uses ajax to submit the data and retrieve the output.
Then in the 'document ready' function the link/button is FancyBoxed. The onStart event is used to store the original contents (the form) to a variable. FancyBox seems to move the form to it's 'Fancybox div' but when it closes, the content is gone. So a subsequent call for the form would fail as it does not exist anymore. The onClosed event is used to restore the original form to its original location.
Put this code below the earlier included jQuery and FancyBox in your page template:
function prepareForm() {
/*
Used to set onSubmit handler. Needs to be done after every ajax request because the old form object is overwritten
*/
$('.frm_ajax_inner form.cms_form').on( "submit", function( event ) {
event.preventDefault();
var posturl = $(this).attr("action") + "?showtemplate=false";
var postdata = $(this).serialize();
var frm_container = $(this).parent();
/* ajax */
$.post(posturl,postdata,function(data) {
/* overwrite form's parent div with new html and prepare form again */
frm_container.html(data);
prepareForm(); } );
} );
}
/*
Variable to get original form content. Used to be able to show a clean form after modal box is closed while form was submitted but not valid
*/
var org_content;
$(document).ready(function() {
$('a.frm_fancybox').fancybox( {
onStart : function (links, index) { /* save original form contents */
var currentlink = $(links[index]);
var linktargetparent = $(currentlink.attr("href") + '_container');
org_content = linktargetparent.html(); } , // save original content to variable
onClosed : function(links, index) { /* restore original hidden form and prepare it */
var currentlink = $(links[index]);
var linktargetparent = $(currentlink.attr("href") + '_container');
linktargetparent.html(org_content);
org_content = '';
prepareForm();}
} );
prepareForm();
} );
</script>
And we need some styling, so add a call to the Fancybox style in the head of your HTML template:
Step 6: Test it
If everything works out well you should now have a working form that shows in a Fancybox and does NOT make your page reload when submitted.
Step 7: Hide the website field (spam prevention)
Use some css to hide the 'website' field from the website visitor. The idea is that automated web bots only look for the form fields and can't resist to add some information. As the specific field is hidden from real, human visitors you know it should never contain anything.
Somewhere in your stylesheet put:
display: none !important;
}
The website field should now not be visible anymore.
Tip
Working example
Comment Form
ReviewManager
ReviewManager
4 Comments
Aha
Thanks, it saved my day! I use latest version of fancybox
Hi, nice script, but not compatible with Fancybox 2.0. Some variables are not passed : function (links, index).
This is working for me, mostly, but when i submit the form using this, I get two sets of results emailed to me, and two confirmations.
It looks like it is sending "multipart/alternative" and "text/plain" versions of the same email, separately. The ajax isn't posting twice, so has to be something with the way it's submitting.
I ran a side-by-side of the output, submitting via ajax vs standard, and in the standard submission, this was at the end of the array:
["cntnt01fbrp_submit"]=> string(1) " "
This is missing from the ajax results. I don't know if this is the issue. If I could even disable HTML emails entirely, this would be better than two emails.