Javascript Ajax Form Submitter with Validation using Jquery

AttachmentSize
form.tpl.php5.08 KB
form.js4.99 KB
This is an example of an ajax form with nice javascript validation. It is nice because it is object oriented and cleanly separated from the global namespace. It uses jquery to do the heavy lifting and thereby makes the code even easier. It contains a good example of email validation as well. Below I'll include the html form code and the javascript the runs on top of it:

HTML

  1. <form enctype="multipart/form-data" action="/form_proxy.php?" method="post" id="example-form">
  2.  
  3. <div class="action-form" id="plugger-form">
  4. <h3>Whaaaat's the deeeeaal?</h3>
  5. <p>Tell us just what the deal is, Kramer!</p><br />
  6.  
  7. <div class="errors"></div><br />
  8.  
  9. <div class="line">
  10. <div id="webform-component-first" class="webform-component-textfield">
  11. <div id="edit-submitted-first-1-wrapper" class="form-item">
  12. <label for="edit-submitted-first-1">First Name <span title="This field is required."
  13. class="form-required">*</span></label>
  14. <input type="text" class="form-text required" value="" size="60"
  15. id="edit-submitted-first-1" name="response.firstName" maxlength="40"/>
  16. </div>
  17. </div>
  18.  
  19. <div id="webform-component-last" class="webform-component-textfield">
  20. <div id="edit-submitted-last-1-wrapper" class="form-item">
  21. <label for="edit-submitted-last-1">Last Name <span title="This field is required."
  22. class="form-required">*</span></label>
  23. <input type="text" class="form-text required" value="" size="60"
  24. id="edit-submitted-last-1" name="response.lastName" maxlength="40"/>
  25. </div>
  26. </div>
  27. </div>
  28.  
  29. <div class="line">
  30. <div id="webform-component-email" class="webform-component-textfield">
  31. <div id="edit-submitted-email-1-wrapper" class="form-item">
  32. <label for="edit-submitted-email-1">Email <span title="This field is required."
  33. class="form-required">*</span></label>
  34. <input type="text" class="form-text required" value="" size="60"
  35. id="edit-submitted-email-1" name="respondent.emailAddress" maxlength="80"/>
  36. </div>
  37. </div>
  38.  
  39. <div id="webform-component-phone" class="webform-component-textfield">
  40. <div id="edit-submitted-phone-1-wrapper" class="form-item">
  41. <label for="edit-submitted-phone-1">Phone <span title="This field is required."
  42. class="form-required">*</span></label>
  43. <input type="text" class="form-text" value="" size="5"
  44. id="edit-submitted-phone-1" name="response.primaryPhNum" maxlength="20"/>
  45. </div>
  46. </div>
  47.  
  48. <div id="webform-component-age" class="webform-component-textfield">
  49. <div id="edit-submitted-age-wrapper" class="form-item">
  50. <label for="edit-submitted-age">Age <span title="This field is required."
  51. class="form-required">*</span></label>
  52. <input type="text" class="form-text" value="" size="60"
  53. id="edit-submitted-age" name="response.age" maxlength="3"/>
  54. </div>
  55. </div>
  56. </div>
  57.  
  58. <div class="line">
  59. <div id="webform-component-address1" class="webform-component-textfield">
  60. <div id="edit-submitted-address1-1-wrapper" class="form-item">
  61. <label for="edit-submitted-address1-1">Street Address <span title="This field is required."
  62. class="form-required">*</span></label>
  63. <input type="text" class="form-text required" value="" size="60"
  64. id="edit-submitted-address1-1" name="response.streetAddress" maxlength="40"/>
  65. </div>
  66. </div>
  67. </div>
  68.  
  69. <div class="line">
  70. <div id="webform-component-city" class="webform-component-textfield">
  71. <div id="edit-submitted-city-1-wrapper" class="form-item">
  72. <label for="edit-submitted-city-1">City <span title="This field is required."
  73. class="form-required">*</span></label>
  74. <input type="text" class="form-text required" value="" size="60"
  75. id="edit-submitted-city-1" name="response.city" maxlength="40"/>
  76. </div>
  77. </div>
  78.  
  79. <div id="webform-component-state" class="webform-component-select">
  80. <div id="edit-submitted-state-1-wrapper" class="form-item">
  81. <label for="edit-submitted-state-1">State <span title="This field is required."
  82. class="form-required">*</span></label>
  83. <select name="response.stateId" id="states">
  84. <option value=""><State></option>
  85. <option value="1">A bunch of US States</option>
  86. </select>
  87. </div>
  88. </div>
  89.  
  90. <div id="webform-component-zip" class="webform-component-textfield">
  91. <div id="edit-submitted-zip-1-wrapper" class="form-item">
  92. <label for="edit-submitted-zip-1">Zip Code <span title="This field is required."
  93. class="form-required">*</span></label>
  94. <input type="text" class="form-text required" value="" size="60"
  95. id="edit-submitted-zip-1" name="response.zip" maxlength="10"/>
  96. </div>
  97. </div>
  98. </div>
  99.  
  100. <div class="line message-line">
  101. <div id="webform-component-message" class="webform-component-textfield">
  102. <div id="edit-submitted-message-wrapper" class="form-item">
  103. <label for="edit-submitted-message">Tell us your story <span title="This field is required."
  104. class="form-required">*</span></label>
  105. <textarea name="response.messageBody" id="text" class="form-text required"></textarea>
  106. </div>
  107. </div>
  108. </div>
  109. </div>
  110. </form>

Javascript

  1. $(document).ready(function() {
  2.  
  3. if ($('form#example-form').length == 0) return;
  4.  
  5. Form($('form#example-form'));
  6. });
  7.  
  8. Form = function(form) {
  9. var self = this;
  10. var errors = new Array();
  11. var submitButtonHTML = $('#submit-button').html();
  12.  
  13. self.validate = function (){
  14. // Clear out old errors
  15. self.clearErrors();
  16.  
  17. // Validate the fields
  18. self.checkNotEmpty('response.firstName', "Please enter your first name");
  19. self.checkNotEmpty('response.lastName', "Please enter your last name");
  20. self.validateEmail();
  21. self.checkNotEmpty('response.primaryPhNum', "Please enter your phone number");
  22. self.validateAge();
  23. self.checkNotEmpty('response.streetAddress', "Please enter your street address");
  24. self.checkNotEmpty('response.city', "Please enter your city");
  25. self.validateState();
  26. self.checkNotEmpty('response.zip', "Please enter your zip code");
  27. self.validateMessage();
  28.  
  29.  
  30. // If we've got errors, render them and bounce
  31. if (errors.length > 0) {
  32. self.renderErrors();
  33. return false;
  34. }
  35.  
  36. return true;
  37. }
  38.  
  39. self.submit = function() {
  40.  
  41. $.ajax({
  42. type: 'POST',
  43. url: form.attr('action'),
  44. data: self.getSubmitPost(),
  45. success: self.submitSuccess,
  46. error: self.submitError
  47. });
  48.  
  49. return false;
  50. }
  51.  
  52. self.getSubmitPost = function() {
  53. var post = new Array;
  54.  
  55. form.find('input').each(function(){
  56. post.push($(this).attr('name') + '=' + $(this).val());
  57. });
  58.  
  59. post.push('response.stateId=' + self.getFieldValue('response.stateId', 'select'));
  60. post.push('response.messageBody=' + self.getFieldValue('response.messageBody', 'textarea'));
  61. return post.join('&');
  62. }
  63.  
  64. self.submitSuccess = function(data) {
  65. window.location.href = Drupal.settings.plugger.thankyou_page;
  66. }
  67.  
  68. self.submitError = function(data) {
  69. errors = new Array();
  70. errors.push("Due to an unusually high volume of submissions, we were unable to
  71. receive your story. We aplogize for the inconvenience. Please try again later!");
  72. self.renderErrors();
  73.  
  74. $('#submit-button').html(submitButtonHTML);
  75. }
  76.  
  77. self.getFieldValue = function(name, type) {
  78.  
  79. if (type == 'select') {
  80. var field = form.find('select[@name=' + name + '] option[@selected]');
  81. } else if (type == 'textarea') {
  82. var field = form.find('textarea[@name=' + name + ']');
  83. } else {
  84. var field = form.find('input[@name=' + name + ']');
  85. }
  86.  
  87. return field.val();
  88. }
  89.  
  90. self.checkNotEmpty = function(name, error) {
  91. var input = form.find('input[@name=' + name + ']');
  92.  
  93. if (input.val() == '') {
  94. input.addClass('error');
  95. errors.push(error);
  96. return false;
  97. }
  98.  
  99. return true;
  100. }
  101.  
  102. self.validateEmail = function() {
  103. var email = form.find('input[@name=respondent.emailAddress]');
  104. var emailRegEx = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
  105.  
  106. if (email.val() == '') {
  107. email.addClass('error');
  108. errors.push("Please enter your email address");
  109. return false;
  110. } else if (!email.val().match(emailRegEx)) {
  111. email.addClass('error');
  112. errors.push("Please enter a valid email address in the form me@doctoroz.com");
  113. return false;
  114. }
  115.  
  116. return true;
  117. }
  118.  
  119. self.validateAge = function() {
  120. var age = form.find('input[@name=response.age]');
  121.  
  122. if (age.val() == '') {
  123. age.addClass('error');
  124. errors.push("Please enter your age");
  125. return false;
  126. } else if (parseInt(age.val()) < 13 ) {
  127. createCookie('under_age', 1, 1);
  128. window.location.href = Drupal.settings.plugger.sorry_page;
  129. }
  130.  
  131. return true;
  132. }
  133.  
  134. self.validateState = function() {
  135. var state = form.find('select[@name=response.stateId]');
  136. var selectedState = state.find('option[@selected]');
  137.  
  138. if (selectedState.val() == '') {
  139. state.addClass('error');
  140. errors.push("Please enter your state");
  141. return false;
  142. }
  143.  
  144. return true;
  145. }
  146.  
  147. self.validateMessage = function() {
  148. var msg = form.find('textarea[@name=response.messageBody]');
  149.  
  150. if (msg.val() == '') {
  151. msg.addClass('error');
  152. errors.push("Please tell us your story");
  153. return false;
  154. }
  155.  
  156. return true;
  157. }
  158.  
  159. self.clearErrors = function() {
  160. form.find('.messages').remove();
  161. form.find('input.error').removeClass('error');
  162. form.find('select.error').removeClass('error');
  163. errors = new Array();
  164. }
  165.  
  166. self.renderErrors = function() {
  167. var out = '<div class="messages error">';
  168.  
  169. if (errors.length > 1) {
  170.  
  171. out += "<ul>";
  172. for (idx in errors) {
  173. out += "<li>" + errors[idx] + "</li>";
  174. }
  175. out += "</ul>";
  176. } else {
  177. out += errors.pop();
  178. }
  179.  
  180. out += '</div>';
  181.  
  182. form.find('.errors').prepend(out);
  183. }
  184.  
  185. form.submit(function(){
  186.  
  187. $('#submit-button').html('Submitting...');
  188.  
  189. if (self.validate()) {
  190. return self.submit();
  191. }
  192.  
  193. $('#submit-button').html(submitButtonHTML);
  194.  
  195. return false;
  196. });
  197. }