Unobtrusive validation with Jquery Steps Wizard

5.4k views Asked by At

Recently I asked a question for how to customize the JQuery Steps as I wanted to use partial views instead of static content. I have partially solved that problem by using the following code supported by jquery-steps,

   <h3>Step 1</h3>
      <section data-mode="async" data-url="/Formation/RenderStep1"></section>

   <h3>Step 2</h3>
      <section data-mode="async" data-url="/Formation/RenderStep2"></section>

Now the big problem I am facing right now is how to use unobtrusive validation. I don't want to use JQuery custom validation and there must be some way of using Obtrusive with it.

Each partial view that is rendered has its own form. I want to validate the form in the onStepChanging function of jquery-steps,

$("#my-steps").steps({
        headerTag: "h3",
        bodyTag: "section",
        contentMode: "async",
        transitionEffect: "fade",
        stepsOrientation: "vertical",

        onStepChanging: function (event, currentIndex, newIndex) {             
            return true;
        }
    });

I have tried calling $.validator.unobtrusvie.parse('#myform'); in the onStepChanging function but ('#myform') is undefined and still I don't know that whether this is the right way to call the unobtrusive validation manually. Kindly guide me and show me the direction to achieve this. Any help will be highly appreciated.

2

There are 2 answers

2
Derek On BEST ANSWER

It sounds like your trying manage multiple forms within the JQuery Steps library and I don't think that is what its intended for.

When you configure JQuery Steps, you set it up against the form in your view.

Unobtrusive JQuery Validation is looking at the model in your view and automatically configuring the HTML with the relevant data attributes for error handling.

This validation should be firing at the client side automatically.

There shouldn't be a problem with using Partial View's, as long as there encapsulated within the same form element.

What is the requirement to have each partial view wrapped in its own form? If your trying to make multiple posts throughout the JQuery Steps form wizard, your defeating the object.

At each step in the JQuery Steps form, your only validating the one form like this :-

onStepChanging: function (event, currentIndex, newIndex) {

                    //Allways allow user to move backwards.

                    if (currentIndex > newIndex) {
                        return true;
                    }

                    // Remove the validation errors from the next step, incase user has previously visited it.

                    var form = $(this);

                    if (currentIndex < newIndex) {

                        // remove error styles
                        $(".body:eq(" + newIndex + ") label.error", form).remove();
                        $(".body:eq(" + newIndex + ") .error", form).removeClass("error");
                    }

                    //disable validation on fields that are disabled or hidden.

                    form.validate().settings.ignore = ":disabled,:hidden";

                    return form.valid();
                }

Once the user has finished entering data, and the client side validation has been met, you hook into the onFinished method and post the form :-

onFinished: function (event, currentIndex) {

                    var form = $(this);
                    form.submit();
                }

The purpose of JQuery Steps is to allow the user to have a fluid experience of filling out a form and to not be overwhelmed with the number of questions been asked.

From the developers perspective, it enables us to split up the form into nice size-able chunks without having to worry about saving progress between screens or losing the state of the form data and allows us to capture all of the required data with only having to make that one post once all validation criteria has been met.

0
Hisham On

I tried the formvalidation plugin, it will relax your mind from searching in validation without form tag or validation without submit the form that's the issue I solved when I tried it.

I know it's not free but you can try it from here, personally I like it

First update height after validation

<style type="text/css">
    /* Adjust the height of section */
    #profileForm .content {
        min-height: 100px;
    }
    #profileForm .content > .body {
        width: 100%;
        height: auto;
        padding: 15px;
        position: relative;
    }

Second, add data-steps index to your section*

<form id="profileForm" method="post" class="form-horizontal">
   <h2>Account</h2>
   <section data-step="0">
    <div class="form-group">
        <label class="col-xs-3 control-label">Username</label>
        <div class="col-xs-5">
            <input type="text" class="form-control" name="username" />
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Email</label>
        <div class="col-xs-5">
            <input type="text" class="form-control" name="email" />
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Password</label>
        <div class="col-xs-5">
            <input type="password" class="form-control" name="password" />
        </div>
    </div>

    <div class="form-group">
        <label class="col-xs-3 control-label">Retype password</label>
        <div class="col-xs-5">
            <input type="password" class="form-control" name="confirmPassword" />
        </div>
    </div>
</section>

Third, javascript code

<script>
## // to adjust step height to fit frame after showing validation messages##
$(document).ready(function() {
  function adjustIframeHeight() {
    var $body   = $('body'),
        $iframe = $body.data('iframe.fv');
    if ($iframe) {
        // Adjust the height of iframe
        $iframe.height($body.height());
    }
}

// IMPORTANT: You must call .steps() before calling .formValidation()
$('#profileForm')
  // setps setup
    .steps({
        headerTag: 'h2',
        bodyTag: 'section',
        onStepChanged: function(e, currentIndex, priorIndex) {
            // You don't need to care about it
            // It is for the specific demo
            adjustIframeHeight();
        },


        // Triggered when clicking the Previous/Next buttons
        // to apply validation to your section 

        onStepChanging: function(e, currentIndex, newIndex) {
            var fv         = $('#profileForm').data('formValidation'), // FormValidation instance
                // The current step container
                $container = $('#profileForm').find('section[data-step="' + currentIndex +'"]');

            // Validate the container
            fv.validateContainer($container);

            var isValidStep = fv.isValidContainer($container);
            if (isValidStep === false || isValidStep === null) {
                // Do not jump to the next step
                return false;
            }

            return true;
        },
        // Triggered when clicking the Finish button
        onFinishing: function(e, currentIndex) {
            var fv         = $('#profileForm').data('formValidation'),
                $container = $('#profileForm').find('section[data-step="' + currentIndex +'"]');

            // Validate the last step container
            fv.validateContainer($container);

            var isValidStep = fv.isValidContainer($container);
            if (isValidStep === false || isValidStep === null) {
                return false;
            }

            return true;
        },
        onFinished: function(e, currentIndex) {
            // Uncomment the following line to submit the form using the defaultSubmit() method
            // $('#profileForm').formValidation('defaultSubmit');

            // For testing purpose
            $('#welcomeModal').modal();
        }
    })
    .formValidation({
        framework: 'bootstrap',
        icon: {
            valid: 'glyphicon glyphicon-ok',
            invalid: 'glyphicon glyphicon-remove',
            validating: 'glyphicon glyphicon-refresh'
        },
        // This option will not ignore invisible fields which belong to inactive panels
        excluded: ':disabled',
        fields: {
            username: {
                validators: {
                    notEmpty: {

                     // for asp.net i used element attribute to integerated with unobtrusive validation 
                     // message :$('username').attr('data-val-required')

                        message: 'The username is required'
                    },
                    stringLength: {
                        min: 6,
                        max: 30,
                        message: 'The username must be more than 6 and less than 30 characters long'
                    },
                    regexp: {
                        regexp: /^[a-zA-Z0-9_\.]+$/,
                        message: 'The username can only consist of alphabetical, number, dot and underscore'
                    }
                }
            },
            email: {
                validators: {
                    notEmpty: {
                        message: 'The email address is required'
                    },
                    emailAddress: {
                        message: 'The input is not a valid email address'
                    }
                }
            },
            password: {
                validators: {
                    notEmpty: {
                        message: 'The password is required'
                    },
                    different: {
                        field: 'username',
                        message: 'The password cannot be the same as username'
                    }
                }
            },
            confirmPassword: {
                validators: {
                    notEmpty: {
                        message: 'The confirm password is required'
                    },
                    identical: {
                        field: 'password',
                        message: 'The confirm password must be the same as original one'
                    }
                }
            }
          }
    });