简体   繁体   中英

contact form Validation with JavaScript multi step form

I currently have a multi-step contact form that uses JavaScript to go to the next step but I need to add input validation so that it checks if the input is selected or filled in before moving to the next steps as currently, it moves on to the next steps without checking if it has been filled in.

//jQuery time
var current_fs, next_fs, previous_fs; //fieldsets
var left, opacity, scale; //fieldset properties which we will animate
var animating; //flag to prevent quick multi-click glitches

$(".next").click(function() {
  if (animating) return false;
  animating = true;

  current_fs = $(this).parent();
  next_fs = $(this).parent().next();

  //activate next step on progressbar using the index of next_fs
  $("#progressbar li").eq($("fieldset").index(next_fs)).addClass("active");

  //show the next fieldset
  next_fs.show();
  //hide the current fieldset with style
  current_fs.animate({
    opacity: 0
  }, {
    step: function(now, mx) {
      //as the opacity of current_fs reduces to 0 - stored in "now"
      //1. scale current_fs down to 80%
      scale = 1 - (1 - now) * 0.2;
      //2. bring next_fs from the right(50%)
      left = (now * 50) + "%";
      //3. increase opacity of next_fs to 1 as it moves in
      opacity = 1 - now;
      current_fs.css({
        'transform': 'scale(' + scale + ')',
        'position': 'absolute'
      });
      next_fs.css({
        'left': left,
        'opacity': opacity
      });
    },
    duration: 800,
    complete: function() {
      current_fs.hide();
      animating = false;
    },
    //this comes from the custom easing plugin
    easing: 'easeInOutBack'
  });
});

$(".previous").click(function() {
  if (animating) return false;
  animating = true;

  current_fs = $(this).parent();
  previous_fs = $(this).parent().prev();

  //de-activate current step on progressbar
  $("#progressbar li").eq($("fieldset").index(current_fs)).removeClass("active");

  //show the previous fieldset
  previous_fs.show();
  //hide the current fieldset with style
  current_fs.animate({
    opacity: 0
  }, {
    step: function(now, mx) {
      //as the opacity of current_fs reduces to 0 - stored in "now"
      //1. scale previous_fs from 80% to 100%
      scale = 0.8 + (1 - now) * 0.2;
      //2. take current_fs to the right(50%) - from 0%
      left = ((1 - now) * 50) + "%";
      //3. increase opacity of previous_fs to 1 as it moves in
      opacity = 1 - now;
      current_fs.css({
        'left': left
      });
      previous_fs.css({
        'transform': 'scale(' + scale + ')',
        'opacity': opacity
      });
    },
    duration: 800,
    complete: function() {
      current_fs.hide();
      animating = false;
    },
    //this comes from the custom easing plugin
    easing: 'easeInOutBack'
  });
});

$(".submit").click(function() {
  return false;
})
#msform {
  max-width: 400px;
  margin: 50px auto;
  text-align: center;
  position: relative;
}

#msform fieldset {
  background: white;
  border: 0 none;
  border-radius: 3px;
  box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.4);
  padding: 20px 30px;
  box-sizing: border-box;
  width: 100%;
  margin: 0 auto;
  /*stacking fieldsets above each other*/
  position: relative;
}


/*Hide all except the first fieldset*/

#msform fieldset:not(:first-of-type) {
  display: none;
}


/*inputs*/

#msform input,
#msform textarea {
  padding: 15px;
  border: 1px solid #ccc;
  border-radius: 3px;
  margin-bottom: 10px;
  width: 100%;
  box-sizing: border-box;
  font-family: montserrat;
  color: #2C3E50;
  font-size: 13px;
}

.field {
  text-align: left;
  width: auto !important;
  border: 1px solid #81e2ff;
  border-top: none;
  padding: 10px;
  #radio-select {
    width: auto;
  }
}


/*buttons*/

#msform .action-button {
  width: 100px;
  background: #27AE60;
  font-weight: bold;
  color: white;
  border: 0 none;
  border-radius: 1px;
  cursor: pointer;
  padding: 10px 5px;
  margin: 10px 5px;
}

#msform .action-button:hover,
#msform .action-button:focus {
  box-shadow: 0 0 0 2px white, 0 0 0 3px #27AE60;
}


/*headings*/

.fs-title {
  font-size: 15px;
  text-transform: uppercase;
  color: #2C3E50;
  margin-bottom: 10px;
}

.fs-subtitle {
  font-weight: normal;
  font-size: 13px;
  color: #666;
  margin-bottom: 20px;
}


/*progressbar*/

#progressbar {
  margin-bottom: 30px;
  overflow: hidden;
  /*CSS counters to number the steps*/
  counter-reset: step;
}

#progressbar li {
  list-style-type: none;
  color: white;
  text-transform: uppercase;
  font-size: 9px;
  width: 33.33%;
  float: left;
  position: relative;
}

#progressbar li:before {
  content: counter(step);
  counter-increment: step;
  width: 20px;
  line-height: 20px;
  display: block;
  font-size: 10px;
  color: #333;
  background: white;
  border-radius: 3px;
  margin: 0 auto 5px auto;
}


/*progressbar connectors*/

#progressbar li:after {
  content: '';
  width: 100%;
  height: 2px;
  background: white;
  position: absolute;
  left: -50%;
  top: 9px;
  z-index: -1;
  /*put it behind the numbers*/
}

#progressbar li:first-child:after {
  /*connector not needed before the first step*/
  content: none;
}


/*marking active/completed steps green*/


/*The number of the step and the connector before it = green*/

#progressbar li.active:before,
#progressbar li.active:after {
  background: #27AE60;
  color: white;
}
<form name="myform" id="msform" action="formhandler.php" method="POST" onsubmit="return validateForm()" onkeydown="return event.key != 'Enter';">
  <!-- progressbar -->
  <!-- fieldsets -->
  <fieldset>
    <h2 class="fs-title">WHERE DO YOU NEED FENCERS?</h2>
    <input type="text" name="postcode" id="search_term" placeholder="Enter postcode or town/city" Autocomplete="off" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>
  <fieldset>
    <h2 class="fs-title">What type of property is this for?</h2>
    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="property" value="House">
      <label for="Property">House</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="property" value="Flat">
      <label for="Property">Flat</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="property" value="Bungalow">
      <label for="Property">Bungalow</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="property" value="commercial place">
      <label for="Property">commercial place</label><br>
    </div>
    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>
  <fieldset>
    <h2 class="fs-title">What does this project invole?</h2>
    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="project" value="install a new fence">
      <label for="Project">install a new fence</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="project" value="install a new gate">
      <label for="Project">install a new gate</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="project" value="Repair an existing fence">
      <label for="Project">Repair an existing fence</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="project" value="Repair an existing gate">
      <label for="Project">Repair an existing gate</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="project" value="Replace an existing fence">
      <label for="Project">Replace an existing fence</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="project" value="Replace an existing gate">
      <label for="Project">Replace an existing gate</label><br>
    </div>

    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>
  <fieldset>
    <h2 class="fs-title">What material would you like for the project?</h2>
    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="material" value="Wood">
      <label for="material">Wood</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="material" value="Steel">
      <label for="material">steel</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="material" value="Vinyl">
      <label for="material">Vinyl</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="material" value="Not Sure Please Recommend">
      <label for="material">Not Sure Please Recommend</label><br>
    </div>
    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>
  <fieldset>
    <h2 class="fs-title">How high should the fence be?</h2>
    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="Under 4 Feet">
      <label for="height">Under 4 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="4 Feet">
      <label for="height">4 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="5 Feet">
      <label for="height">5 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="6 Feet">
      <label for="height">6 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="7 Feet">
      <label for="height">7 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="8 Feet">
      <label for="height">8 Feet</label><br>
    </div>


    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="Over 8 Feet">
      <label for="height">Over 8 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="height" value="As recommended by professional">
      <label for="height">As recommended by professional</label><br>
    </div>


    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>
  <fieldset>
    <h2 class="fs-title">How long will the fence approximately be??</h2>
    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="Under 50 Feet">
      <label for="length">Under 50 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="50-100 Feet">
      <label for="length">50-100 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="100-200 Feet">
      <label for="length">100-200Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="200-300 Feet">
      <label for="length">200-300 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="Over 300 Feet ">
      <label for="length">Over 300 Feet</label><br>
    </div>

    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="I'm not sure">
      <label for="length">I'm not sure</label><br>
    </div>


    <div class="field" id="property-radio">
      <input type="radio" id="radio-select" name="length" value="Other">
      <label for="length">Other</label><br>
    </div>
    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>

  <fieldset>
    <h2 class="fs-title">What email address would you like your quote sent to?</h2>
    <input type="email" name="email" placeholder="email address" />
    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>

  <fieldset>
    <h2 class="fs-title">What is your phone number?</h2>
    <input type="tel" name="phone" placeholder="Phone Number" />
    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <input type="button" name="next" class="next action-button" value="Next" />
  </fieldset>

  <fieldset>
    <h2 class="fs-title">What email address would you like your quote sent to?</h2>
    <input type="text" name="fname" placeholder="email address" />
    <input type="button" name="previous" class="previous action-button" value="Previous" />
    <button type="submit" class="next action-button">Submit</button>
  </fieldset>
</form>

I have created a working fiddle that shows how to use jQuery Validate with your code for the first two steps in your progression of steps.

This is what I did:

Loaded the jquery validate plugin:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js" integrity="sha512-0QDLUJ0ILnknsQdYYjG7v2j8wERkKufvjBNmng/EdR/s/SE7X8cQ9y0+wMzuQT0lfXQ/NhG+zhmHNOWTUS3kMA==" crossorigin="anonymous"></script>

Added a data-step="#" attribute/value to your <fieldset> elements that we can use to determine what step # we are on when the "next" button is clicked.

<fieldset data-step="1">

Added a class name of "property-type" to all of the radio inputs in step 2. We will use this class as the target of our validation for step 2, shown further below. I also renamed all of the ID's to be unique! (you will need to fix this on your other inputs - I only fixed them in step 2). Eg:

<input type="radio" class="property-type" id="property-type-1" name="property" value="House">

I added a doc ready function to your JS code and moved your existing click event bindings into it.

$(document).ready(function(){
   
   // moved your existing click event binding definitions here
});

I defined a global variable, msformValidation, and then inside doc ready I instantiated a new jquery validation object which is stored in this variable.

The validation rules are passed in as an argument to the plugin's instantiator function. It's important to note that rules are defined for the NAME of an inpu. (Not an input's type, id, or class!)

msformValidation = $('#msform').validate({
    submitHandler: function () { }, // prevent traditional form submission
    rules:{
        'postcode': { // this is the input name for the first step
            required: true        
         },
         'property': { // this is the input name of the radio group in the second step
             required: true
         }
     }  
  });

Now the only thing left to do is modify the function handler for when the next button is clicked:

$(".next").click(function() {
   if (animating) return false;
   animating = true;

   current_fs = $(this).parent();

   // run the validations on the input for the current step    
   var validationPassed = false;
   if(current_fs.data('step') == 1){                  
      validationPassed = $('#search_term').valid();
   }else if(current_fs.data('step') == 2){
      validationPassed = $('.property-type').valid();
   }

   // check to see if the validator for the specific step we are on passed or not.
   if(validationPassed == false){
     // do not proceed!
     animating = false;
     return;
   }        
    
   // .. proceed with your code..

Note that UNLIKE how rules are defined using an input's name, checking if a specific input is .valid() DOES use an inputs ID, eg: $('#search_term').valid(); , except for radio groups which then you use a distinct common class name that is assigned to all of the inputs in the same group, eg: $('.property-type').valid(); .

Also note that, I added a <label> element at the end of the radio group list to specifically position where I want any validation error messages to show up. If I didn't add this then the message, in this case, would always show up underneath the first radio input.

<label id="property-error" class="error" for="property"></label>

The ID value you assign to this label matters! It's the {input NAME}-error

The plugin is actually pretty easy to use once you know when to use an input's name, versus it's id, versus it's class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM