Step by step checkbox process with summary of sele

2019-07-30 23:23发布

I'm trying to create a 3 step process where someone selects the items they want on steps 1 and 2 via checkboxes, then on the third step it shows a summary of those selections.

This is how my html is setup:

<form id="customisesystem" method="post" action="">
  <div id="first-step">
    <div class="steps">
      <p><b>Step 1 of 3</b></p>
    </div>
    <div class="progress-buttons"></div>
    <div class="clear"></div>
    <div id="customise-area">
      <div id="customise-title">
        <p><b>1. Hardware &amp; software options</b> <span>Please choose one or more of the following</span></p>
      </div>
      <div id="customise-area">
        <?php $posts = get_field('options');
                            if( $posts ):
                            $items = 0;
                            foreach( $posts as $post): // variable must be called $post (IMPORTANT)
                                setup_postdata($post); ?>
        <div class="custom-option">
          <p><b>
            <?php the_title(); ?>
            </b></p>
          <br />
          <div> <?php echo the_content(); ?> </div>
          <?php $counter = 1; while(the_repeater_field('images')): ?>
          <?php if($counter <= 1) { ?>
          <img width="180" height="136" src="<?php the_sub_field('image'); ?>" alt="<?php the_title(); ?>" />
          <?php } ?>
          <?php $counter++; endwhile; ?>
          <p>
            <input type="checkbox" name="hardware[]" value="<?php the_title(); ?>">
            Select</p>
          <div class="clear"></div>
        </div>
        <?php $items++; endforeach;
                            wp_reset_postdata(); // IMPORTANT - reset the $post object so the rest of the page works correctly
                            endif; ?>
      </div>
    </div>
  </div>
  <!-- end first-step -->

  <div id="second-step">
    <div class="steps">
      <p><b>Step 2 of 3</b></p>
    </div>
    <div class="progress-buttons"></div>
    <div class="clear"></div>
    <div id="customise-area">
      <div id="customise-title">
        <p><b>2. Accessories</b> <span>Please choose one or more of the following</span></p>
      </div>
      <div id="customise-area">
        <?php $posts = get_field('accessories');
                            if( $posts ):
                            $items = 0;
                            foreach( $posts as $post): // variable must be called $post (IMPORTANT)
                                setup_postdata($post); ?>
        <?php if ($items&1) { ?>
        <div class="custom-option">
          <p><b>
            <?php the_title(); ?>
            </b></p>
          <br />
          <div> <?php echo the_content(); ?> </div>
          <?php $counter = 1; while(the_repeater_field('images')): ?>
          <?php if($counter <= 1) { ?>
          <img width="180" height="136" src="<?php the_sub_field('image'); ?>" alt="<?php the_title(); ?>" />
          <?php } ?>
          <?php $counter++; endwhile; ?>
          <p>
            <input type="checkbox" name="accessories[]" value="<?php the_title(); ?>">
            Select</p>
          <div class="clear"></div>
        </div>
        <?php } else { ?>
        <div class="custom-option">
          <p><b>
            <?php the_title(); ?>
            </b></p>
          <br />
          <div> <?php echo the_content(); ?> </div>
          <?php $counter = 1; while(the_repeater_field('images')): ?>
          <?php if($counter <= 1) { ?>
          <img width="180" height="136" src="<?php the_sub_field('image'); ?>" alt="<?php the_title(); ?>" />
          <?php } ?>
          <?php $counter++; endwhile; ?>
          <p>
            <input type="checkbox" name="accessories[]" value="<?php the_title(); ?>">
            Select</p>
          <div class="clear"></div>
        </div>
        <?php } ?>
        <?php $items++; endforeach;
                            wp_reset_postdata(); // IMPORTANT - reset the $post object so the rest of the page works correctly
                            endif; ?>
      </div>
    </div>
  </div>
  <!-- end second-step -->

  <div id="third-step">
    <div class="steps">
      <p><b>Step 3 of 3</b></p>
    </div>
    <div class="progress-buttons"></div>
    <div class="clear"></div>
    <div id="customise-area-3">
        <p>Summary</p>

        <div id="customise-area-3-child">
            <input type="submit" name="submit" id="submit" value="submit" />
        </div>
    </div>
  </div>
  <!-- end third-step -->

</form>

This is my jquery for stepping through the process:

var prevLink = '<a class="back" href="#">Back</a>';
var nextLink = '</a><a class="next" href="#">Next</a>';
var navHTML = '<div class="prev-next">' +
                         prevLink +
                         nextLink +
                      '</div>';
var prevLink = '<a class="back" href="#">Back</a>';
var nextLink = '</a><a class="next" href="#">Next</a>';
var navHTML = '<div class="prev-next">' +
                         prevLink +
                         nextLink +
                      '</div>';
jQuery(document).ready(function( $ ) {
            // init
            $('#customisesystem > div')
                .hide()
                .prepend(navHTML);
            $('#first-step .prev').remove();
            $('#last-step .next').remove();

            // show first step
            $('#first-step').show();

            $('a.next').click(function(){
                var whichStep = $(this).parent().parent().attr('id');

                if( whichStep == 'first-step' )
                {
                    // validate first-step
                }
                else if( whichStep == 'second-step' )
                {
                    // validate second-step
                }
                else if( whichStep == 'last-step' )
                {
                    // validate last-step
                }

                $(this).parent().parent().hide().next().show();
            });

 $('a.back').click(function(){
          var whichStep = $(this).parent().parent().attr('id');
          if(whichStep == "first-step"){
            $(".customise").hide();
            $(".entire_product").show();
          }
          else{
            $(this).parent().parent().hide().prev().show();
          }
 });
        });

Here's the part that isn't working:

jQuery(document).ready(function( $ ) 
{
   var summary = $('#customise-area-3 p').get(0);

   $('input[type=checkbox][name="hardware[]"]:checked').each(function(k,v) {
    //Retrieve the value of the checkbox.
    var checkboxValue = v.val();

    //Add the checkbox value to the summary area:
    summary[0].innerHTML += checkboxValue + '<br />';
   });
});

At the moment, when I've made the hardware selections and goto the third step it doesn't show any information in the summary. Where am I going wrong?

Here's the working link - teamworksdesign.com/clients/rogue/system/dc-stimulator click on "get quotation" on the right. That will show step 1, click next for step 2, then next for step 3 (i.e the summary).

1条回答
疯言疯语
2楼-- · 2019-07-30 23:50

Things get easier if the "step" divs are all given class="step", thus allowing them to be selected with jQuery(".step"), and avoiding the need for each one to have a unique id.

Your specific question is answered by including, in the last step, a "Validate" button, which performs the validation. If the last step is valid :

  • Summary text is created and displayed
  • The "Validate" button is hidden and a "Submit" button is shown.

This last feature ensures that the form can't be submitted until the last step is validated and that the user can read the Summary before the screen is refreshed.

Here's the code (laced with comments) :

//create nav wrapper
var $nav = $('<div/>').addClass('prev-next');

//create Prev button, attach click handler and append to nav wrapper
$('<a class="prev" href="#">Back</a>').on('click', function () {
    $(this).closest(".step").hide().prev(".step").show();
}).appendTo($nav);

//create Next button, attach click handler and append to nav wrapper
$('<a class="next" href="#">Next</a>').on('click', function () {
    var $step = $(this).closest(".step");
    if (validate($step)) {
        $step.hide().next(".step").show();
    }
}).appendTo($nav);

//In one long jQuery chain ...
//* prepend nav to each step div
//* hide all steps except the first
//* convert first 'Back' link and last 'Next' link to spans.
$(".step").prepend($nav).hide()
    .filter(":first").show().find("a.prev").after('<span>Back</span>').remove().end().end()
    .filter(":last").find("a.next").after('<span>Prev</span>').remove();

//Last step doesn't have a "Next" button but does have a "Validate" button
//and a submit button, which is hidden until the last step is validated,
//thus allowing the Summary message to be shown.
//Otherwise, the summary message would appear only for a brief moment.
var $validateButton = $("#validate").on('click', function() {
    if( validate( $(".step:last") ) ) {
        //var summary = [];
        var summary = ["Test Message"];//for debugging
        $('input[type=checkbox][name="hardware[]"]:checked').each(function(i, ch) {
            summary.push($(ch).val());
        });
        $('#customise-area-3 p').html(summary.join('<br/>'));
        $(this).hide();
        $("input[name='submit']").show();
    }
});

//Unfortunately, hidden form elements are not inlcuded in the submission,
//so all steps must be shown before the form is submitted.
var $submitButton = $("input[name='submit']").on('submit', function() {
    $(".step").show();
    return true;
});

function validate($step) {
    //var valid = false;
    var valid = true;//for debugging

    //Set the last section's validate and submit buttons to their "unvalidated" states.
    $validateButton.show();
    $("input[name='submit']").hide();

    //Perform validation
    switch ($step.index(".step")) {//index-origin is zero
        case 0:
            //validate step 1 here
            //if valid, set `valid` to true 
        break;
        case 1:
            //validate step 2 here
            //if valid, set `valid` to true 
        break;
        case 2:
            //validate step 3 here
            //if valid, set `valid` to true 
        break;
    }
    return valid;//Important - determines behaviour after validate() returns.
}

Here's a DEMO

You will see that I made some other minor modifications to the HTML, in particular to add the Validate button in the last step.

EDIT

If the last step is solely for displaying the Summary and requires no validation of its own, then things are simpler :

//Create nav wrapper
var $nav = $('<div/>').addClass('prev-next');

//Create Prev button, attach click handler and append to nav wrapper
$('<a class="prev" href="#">Back</a>').on('click', function() {
    $(this).closest(".step").hide().prev(".step").show();
}).appendTo($nav);

//Create Next button, attach click handler and append to nav wrapper
$('<a class="next" href="#">Next</a>').on('click', function() {
    $('#summary_text').html(makeSummary());
    var $step = $(this).closest(".step");
    if (validate($step)) {
        $step.hide().next(".step").show();
    }
}).appendTo($nav);

//In one long jQuery chain ...
//* prepend nav to each step div
//* hide all steps except the first
//* convert first 'Back' link and last 'Next' link to spans.
var $steps = $(".step").prepend($nav).hide()
    .filter(":first").show().find("a.prev").after('<span>Back</span>').remove().end().end()
    .filter(":last").find("a.next").after('<span>Prev</span>').remove().end().end();

//Set step titles
$steps.each(function(i, step) {
    $(step).find(".step-title").text('Step ' + (i+1) + ' of ' + $steps.length);
});

//Unfortunately, hidden form elements are not inlcuded in the submission,
//so all steps must be shown before the form is submitted.
var $submitButton = $("input[name='submit']").on('submit', function() {
    $steps.show();
    return true;
});

function validate($step) {
    //var valid = false;
    var valid = true;//for debugging

    //Perform validation
    switch ($step.index(".step")) {//index-origin is zero
        case 0:
            //Validate step 1 here
            //if valid, set `valid` to true 
        break;
        case 1:
            //Validate step 2 here
            //if valid, set `valid` to true 
        break;
        case 2:
            //No validatation required
        break;
    }
    return valid;//Important - determines behaviour after validate() returns.
}

function makeSummary() {
    var summary = [];
    $steps.not(":last").each(function(i, step) {
        $step = $(step);
        summary.push('<h4>' + $step.data('name') + '</h4>');
        var $ch = $step.find('input[type="checkbox"]:checked');
        if(!$ch.length) {
            summary.push('<p>No items selected</p>');
        }
        else {
            $ch.each(function(i, ch) {
                summary.push('<p>' + $(ch).val() + '</p>');
            });
        }
    });
    return summary.join('');
}

DEMO

In the demo, you will find further mods to the HTML and CSS.

Notes :

  • Unless I've missed something, the javascript should now be automatically responsive to more/less steps. So if the customer was to change his mind and wanted to split Hardware and software into separate steps, you would only need to change the HTML. (Oh yes, and the validation() function - that is a special case).
  • The "Step X of Y" text is now automatically generated and requires just <h2 class="step-title"></h2> in the HTML.
  • Now requires a data-name attribute in the first and second step divs. This is used in the Summary.
  • The summary is formatted; uses <p> elements instead of <br>; includes <h4> section headers.
  • "Validate" button now removed from the last step.
  • Various additional/modified CSS directives.
查看更多
登录 后发表回答