nickpish
nickpish

Reputation: 847

Progress bar indicating form completion in jQuery

I'm working on a progress bar using the progress element that increases as the user completes fields in a lengthy form. I found this SO thread which was helpful in getting some baseline functionality using a data-* attribute, but my form has a "Save Progress" feature that will save any entered field information to the browser's local storage to be retrieved later. Thus, in the event that a user returns to the form with saved data, I'd like the bar to reflect that level of progress.

Here's what is working thus far- sample markup using the data-attribute data-prog for a form field:

<!-- FORM - SAMPLE FIELD -->
<div id="form">
<div class="field-group required">
   <label for="mgd_org_name">Organization Name:</label>
   <div>
      <input id="mgd_org_name" type="text" name="mgd_org_name" placeholder="Please enter your organization's name" required data-prog="6">
   </div>
</div>
</form>

<!-- Progress bar -->
<div id="form-progress">
    <p>Form Progress</p>
    <progress max="100" value="0" id="progress"></progress>
</div>

And the jQuery thus far:

$(function() {
    // get all form inputs w/ data-prog values
    var inputs = $('#dossier-form').find('input[data-prog], textarea[data-prog]');
    var progBar = $('#progress');
    var progVal = 0;

    $(inputs).change(function() {
        if ($(this).val().length > 0) {
            progVal += $(this).data('prog');
            progBar.attr('value', progVal);
        }
    });

});

In this way, each field has a data-prog value that will be added to the progVal and reflected in the progress bar level. What I'm having trouble with is loading an initial value for any form fields that might already be filled on load—thus, I would need to find all fields that have a value entered, add the associated data-prog values, and initially load that value into the progress bar. I would also like to accordingly decrease the progress value in the event that a field is cleared.

For the initial load, I've been trying something like the following (not working):

var inputsSaved = $(inputs).val();
if($(inputsSaved).length > 0) {
    progVal = $(inputs).data('prog');
    console.log('has existing progress');
} else {
    progVal = 0;
    console.log('does not have existing progress');
}

I'm not quite sure how to find the fields with text entered on load and grab the associated prog values nor how to decrease the value accordingly if a field is cleared. Any assistance here is greatly appreciated!

Upvotes: 0

Views: 1108

Answers (2)

Louys Patrice Bessette
Louys Patrice Bessette

Reputation: 33933

First, your inputs selector can be replaced by:

var inputs = $('#dossier-form [data-prog]');

Then, $(inputs).change(..., inputs already is a jQuery object. No need to wrap it with $().

You had the progress update function correct. I just placed it in a named function to be able to call it from different places in code (and avoid duplicate code).

I added the localStorage save and retreive...

$(function() {

  // get all form inputs w/ data-prog values
  var inputs = $('#dossier-form [data-prog]');
  var progBar = $('#progress');
  var progVal = 0;

  // Establish the "dificulty unit" base.
  var totalDifficulty = 0;
  inputs.each(function(){
    totalDifficulty += $(this).data('prog');
  });

  var difficultyUnit = 100/totalDifficulty;

  // Update progressbar
  function updateProgress(el){
    progVal += parseFloat($(el).data('prog')) * difficultyUnit;
    progBar.val(progVal);
  }

  // LocalStorage on load
  inputs.each(function(){
    var value = localStorage.getItem(this.id);
    if(value !=null && value !=""){
      $(this).val(value);
      updateProgress(this);
    }
  });  // End load from LocalStorage

  // Blur handler to save user inputs
  inputs.on("blur",function(){
    // Reset the progress
    progVal = 0;
    progBar.val(progVal);

    // Loop through all inputs for progress
    inputs.each(function(){
      if ($(this).val().length > 0) {
        updateProgress(this);
      }

      // LocalStorage
      localStorage.setItem(this.id,this.value);
    });
  });  // End on blur

});  // End ready

localStorage isn't allowed in the SO snippets... So have a look at this CodePen.


So you can now give some "difficulty level" without worring about the total obtained by all the data-prog to be 100. Just give an arbitrary number you feel like. ;)

Upvotes: 1

Ben West
Ben West

Reputation: 4596

If you always add up the progress from scratch, you can do the same thing in both cases.

$(function() {

    // get all form inputs w/ data-prog values
    var inputs = $('#dossier-form').find('input[data-prog], textarea[data-prog]');
    var progBar = $('#progress');

    function update () {
        var progVal = 0;
        inputs.each( function () {
            if ($(this).val().length > 0) {
                progVal += Number( $(this).data('prog') );
            }
        })
        progBar.attr('value', progVal);
    }

    inputs.change( update );

    // Fill in fields from localStorage, then:
    update();

});

Upvotes: 1

Related Questions