Skip to content
This repository has been archived by the owner on Aug 6, 2019. It is now read-only.

Step Validation using onNext event. #12

Closed
scottyc opened this issue Jan 31, 2013 · 22 comments
Closed

Step Validation using onNext event. #12

scottyc opened this issue Jan 31, 2013 · 22 comments

Comments

@scottyc
Copy link

scottyc commented Jan 31, 2013

I am using the jquery.validation from the base MVC 4 project in Visual Studio 2012.
I needed a way to validate only the fields in the current step.
I looked at the example of the form validation, but it seemed to be leading toward a nightmare of hard coded items that couldn't be reused and difficult to maintain.

I thought I would share my first implementation of the step validation using the onNext event. My step containers are


It seems that the tab object in the function is a reference to the actual navigation tab and not the step container.

If you see room for improvements, please let me know as I am not a js ninja :)

{

onNext: function (tab, navigation, index) {

                    var isValid = false;
                    var hadError = false;
                    var tabs = $(".tab-pane");
                    var currentTab = tabs[index - 1]; 
                    var inputs = $(":input");
                    var stepElements = $(currentTab).find(inputs);
                    var count = stepElements.length;
                    if (count <= 0) {
                        return true;
                    }
                    $(stepElements).each(function (idx) {
                        isValid = $(document.forms[0]).validate().element($(this));
                        if (!isValid) { hadError = true; }
                    });

                    return !hadError;

            },

}

@VinceG
Copy link
Owner

VinceG commented Feb 1, 2013

Hey Scott,

Reading this i think it should be placed under the Wiki section as this appears to be just a tip rather then an Issue.

Thanks.

@gilluminate
Copy link
Contributor

Vince, It looks like clicking the Wiki button doesn't do anything at the moment. At least not for me.

@scottyc
Copy link
Author

scottyc commented Feb 8, 2013

I don’t even see the wiki button now, yesterday it had no action.

Have you had any success on getting the nested wizards to work?

scottyc

From: Jason Gill [mailto:notifications@github.com]
Sent: Friday, February 08, 2013 12:47 AM
To: VinceG/twitter-bootstrap-wizard
Cc: scottyc
Subject: Re: [twitter-bootstrap-wizard] Step Validation using onNext event. (#12)

Vince, It looks like clicking the Wiki button doesn't do anything at the moment. At least not for me.


Reply to this email directly or view it on GitHub #12 (comment) .

https://github.com/notifications/beacon/J6T91GIPIyhU-8ti4GCGP7m2EBfP5A8296qsIQLYZalbjLi1TkbUXkCm_cFKwo7V.gif

@scottyc
Copy link
Author

scottyc commented Feb 8, 2013

I saw the custom styles example,

$('#rootwizard').bootstrapWizard({'nextSelector': '.button-next', 'previousSelector': '.button-previous'});

You may have already had the same thought I just did, but …

It would be neat to create a configuration .js file similar to the way the ckeditor does (config.js).

Then push custom “themes” to a “themes/” folder similar to the way that jqueryUI does.

At that point a theme could be made based on color, tab style, next/previous button style and specified with the theme name in the config.js file. (theme: ‘arrowtabs-blue’ or theme:’arrowtabs-red’)

The granular control would also be there is the user wanted to specify settings in the config.js or inline like you have in the example.

scottyc

From: Jason Gill [mailto:notifications@github.com]
Sent: Friday, February 08, 2013 12:47 AM
To: VinceG/twitter-bootstrap-wizard
Cc: scottyc
Subject: Re: [twitter-bootstrap-wizard] Step Validation using onNext event. (#12)

Vince, It looks like clicking the Wiki button doesn't do anything at the moment. At least not for me.


Reply to this email directly or view it on GitHub #12 (comment) .

https://github.com/notifications/beacon/J6T91GIPIyhU-8ti4GCGP7m2EBfP5A8296qsIQLYZalbjLi1TkbUXkCm_cFKwo7V.gif

@VinceG
Copy link
Owner

VinceG commented Feb 9, 2013

Wiki should be working now. I'm still working on the nested wizards bug.

@neara
Copy link

neara commented Mar 28, 2013

Hi!

I'm using jquery.validate plugin for form validation. After a few tweaks i finally got it to work.
It seems that returning false in onNext function doesn't prevent the user from moving to next step in wizard.

If it's not a bug, then what am I missing? How to prevent the wizard from moving on before all fields in current step are valid?

Here is my onNext function:

onNext: function (tab, navigation, index) {
            console.log('in on next');

            if (!form.valid()) {
                console.log('not valid');
                $('.error').first().focus();
                return false;
            }

            var total = navigation.find('li').length;
            var current = index + 1;
            // set wizard title
            $('.step-title', form).text('Step ' + (index + 1) + ' of ' + total);
            // set done steps
            jQuery('li', form).removeClass("done");
            var li_list = navigation.find('li');
            for (var i = 0; i < index; i++) {
                jQuery(li_list[i]).addClass("done");
            }

            if (current == 1) {
                form.find('.button-previous').hide();
            } else {
                form.find('.button-previous').show();
            }

            if (current >= total) {
                form.find('.button-next').hide();
                form.find('.button-submit').show();
            } else {
                form.find('.button-next').show();
                form.find('.button-submit').hide();
            }

            App.scrollTo($('.page-title'));
        },

I've tried other things as well, you can see more here: http://stackoverflow.com/questions/15679469/twitter-bootstrap-form-wizard-jquery-validate-prevent-user-from-moving-to-next
And in every case the wizard still moved on to next step.

thank you for your help

@scottyc
Copy link
Author

scottyc commented Mar 28, 2013

Change:

               if (!form.valid()) {
                   console.log('not valid');
                   $('.error').first().focus();
                   return false;
               }

To get the form fields only in the current step and validate them.

                var isValid = false;
                // var hadError = false; // You don't need this flag with the change on the validation loop. 
                var tabs = $(".tab-pane"); // get all steps 
                var currentTab = tabs[index - 1];  // get the current step 
                var inputs = $(":input"); // get all inputs
                var stepElements = $(currentTab).find(inputs); // get all inputs in the current step 
                var count = stepElements.length;
                if (count <= 0) { // if no inputs just return true to move to the next step. 
                    return true;
                }
                $(stepElements).each(function (idx) {
                    isValid = $(document.forms[0]).validate().element($(this));
                    // to stop at the first error and set focus on that field then you can do that here. 

                    if(!isValid) {
                        $('.error').first().focus();
                        return isValid;
                    }

                    // if (!isValid) { hadError = true; }
                });

               // return !hadError;
               return true; // with the change on the validation loop, if you make it here then all fields in the step are valid so just return true and move to the next step. 

@neara
Copy link

neara commented Mar 28, 2013

The only way is a field by field validation? and stop on every invalid field?

So, lets say the user has all fields wrong, worst case scenario, your way the user will go back for every field, every time he will try to submit. I have 6 fields, the user will click 6 times submit, and 6 times fail?

Is there no way to turn on/off the wizard's transfer?

@neara
Copy link

neara commented Mar 28, 2013

Ok, i found how to make this work the way i want it.

Here is the solution:

onNext: function (tab, navigation, index) {
            console.log('in on next');

            var allowStep = form.valid();

            if (allowStep) {

                var total = navigation.find('li').length;
                var current = index + 1;
                // set wizard title
                $('.step-title', form).text('Step ' + (index + 1) + ' of ' + total);
                // set done steps
                jQuery('li', form).removeClass("done");
                var li_list = navigation.find('li');
                for (var i = 0; i < index; i++) {
                    jQuery(li_list[i]).addClass("done");
                }

                if (current == 1) {
                    form.find('.button-previous').hide();
                } else {
                    form.find('.button-previous').show();
                }

                if (current >= total) {
                    form.find('.button-next').hide();
                    form.find('.button-submit').show();
                } else {
                    form.find('.button-next').show();
                    form.find('.button-submit').hide();
                }

                App.scrollTo($('.page-title'));
            }

            return allowStep;
        },

I still don't get tho, why if statement at the beginning didn't work.

@scottyc
Copy link
Author

scottyc commented Mar 28, 2013

With the example of the onNext event I originally posted, it checks that the current step form fields are valid. It appeared in your post you wanted to stop at the first field that had an error.

You return false from the onNext event to prevent moving to the next step.

onNext : Fired when next button is clicked (return false to disable moving to the next step)
http://vadimg.com/twitter-bootstrap-wizard-example/#docs

On the validation side of things, you want to make sure that you only validate the items in the currently displayed step. I do it step by step because I want to check the items in the current step only and display thier error messages if invalid. I already know that steps after the current step is going to contain invalid entry if I check all form fields.

here is my full onNext event that is working in the final build of the project I used this on:

               onNext: function (tab, navigation, index) {

                var isValid = false;
                var hadError = false;
                var tabs = $(".tab-pane");
                var currentTab = tabs[index - 1];
                var inputs = $(":input, select");
                var stepElements = $(currentTab).find(inputs);
                var count = stepElements.length;
                if (count <= 0) {
                    return true;
                }
                $(stepElements).each(function (idx) {
                    isValid = $(document.forms[0]).validate().element($(this));
                    if (!isValid) { hadError = true; }
                });


                if (hadError == false) {


                    if (index == navigation.find('li').length) {
                        $("form").submit();
                    }

                }



                return !hadError;
        }

@neara
Copy link

neara commented Mar 28, 2013

I'm validating all fields in current step using jquery.validate plugin. As I said, i wanted to stop the wizard from going on to the next step, if there were any errors in fields in current step. I have only one form, being submitted at the end of last step.

I returned false from if statement inside onNext function. Why it didn't work? I saw that indeed all lines after the return were not executed, but the wizard still continued on. I'm not an expert on javascript, but my understanding of programming says, it should have had the same effect as the solution i posted later on: even from inside if statement in a function, return should stop the execution of this function and return whatever i told it to return.

Anyways, i found a solution to my problem and posted it in a comment. I think this case might be a good wiki page, unfortunately i don't have the time atm.

thank you for your help :)

On Mar 28, 2013, at 4:40 PM, scottyc notifications@github.com wrote:

With the example of the onNext event I originally posted, it checks that the current step form fields are valid. It appeared in your post you wanted to stop at the first field that had an error.

You return false from the onNext event to prevent moving to the next step.

onNext : Fired when next button is clicked (return false to disable moving to the next step)
http://vadimg.com/twitter-bootstrap-wizard-example/#docs

On the validation side of things, you want to make sure that you only validate the items in the currently displayed step. I do it step by step because I want to check the items in the current step only and display thier error messages if invalid. I already know that steps after the current step is going to contain invalid entry if I check all form fields.

here is my full onNext event that is working in the final build of the project I used this on:

           onNext: function (tab, navigation, index) {

            var isValid = false;
            var hadError = false;
            var tabs = $(".tab-pane");
            var currentTab = tabs[index - 1];
            var inputs = $(":input, select");
            var stepElements = $(currentTab).find(inputs);
            var count = stepElements.length;
            if (count <= 0) {
                return true;
            }
            $(stepElements).each(function (idx) {
                isValid = $(document.forms[0]).validate().element($(this));
                if (!isValid) { hadError = true; }
            });


            if (hadError == false) {


                if (index == navigation.find('li').length) {
                    $("form").submit();
                }

            }



            return !hadError;
    }


Reply to this email directly or view it on GitHub.

@VinceG
Copy link
Owner

VinceG commented Mar 28, 2013

I am going to write a blog post and add some examples for using the wizard with the JQuery validation plugin.

Sorry for the confusion.

Please excuse my brevity, sent from my iPhone.

On Mar 28, 2013, at 8:02, Ana notifications@github.com wrote:

I'm validating all fields in current step using jquery.validate plugin. As I said, i wanted to stop the wizard from going on to the next step, if there were any errors in fields in current step. I have only one form, being submitted at the end of last step.

I returned false from if statement inside onNext function. Why it didn't work? I saw that indeed all lines after the return were not executed, but the wizard still continued on. I'm not an expert on javascript, but my understanding of programming says, it should have had the same effect as the solution i posted later on: even from inside if statement in a function, return should stop the execution of this function and return whatever i told it to return.

Anyways, i found a solution to my problem and posted it in a comment. I think this case might be a good wiki page, unfortunately i don't have the time atm.

thank you for your help :)

On Mar 28, 2013, at 4:40 PM, scottyc notifications@github.com wrote:

With the example of the onNext event I originally posted, it checks that the current step form fields are valid. It appeared in your post you wanted to stop at the first field that had an error.

You return false from the onNext event to prevent moving to the next step.

onNext : Fired when next button is clicked (return false to disable moving to the next step)
http://vadimg.com/twitter-bootstrap-wizard-example/#docs

On the validation side of things, you want to make sure that you only validate the items in the currently displayed step. I do it step by step because I want to check the items in the current step only and display thier error messages if invalid. I already know that steps after the current step is going to contain invalid entry if I check all form fields.

here is my full onNext event that is working in the final build of the project I used this on:

onNext: function (tab, navigation, index) {

var isValid = false;
var hadError = false;
var tabs = $(".tab-pane");
var currentTab = tabs[index - 1];
var inputs = $(":input, select");
var stepElements = $(currentTab).find(inputs);
var count = stepElements.length;
if (count <= 0) {
return true;
}
$(stepElements).each(function (idx) {
isValid = $(document.forms[0]).validate().element($(this));
if (!isValid) { hadError = true; }
});

if (hadError == false) {

if (index == navigation.find('li').length) {
$("form").submit();
}

}

return !hadError;
}

Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub.

@VinceG VinceG closed this as completed in 7750f22 Apr 1, 2013
@frgooall
Copy link

@neara @VinceG I followed your step validation and had success preventing the users from going on to the next step, so thank you for your snippet, very helpful!

What I can't figured out is how to get the next button to work when the user submit valid information.

User does not submit (in my case, not click a checkbox) valid info...form stops, error is displayed => User click on or submits valid info then tries to proceed, but the next button does not take user to next step, it just hangs. I know it probably needs some sort of refresh, but can't find a way to hook into the invalid action. Any suggestions?

Thank you!

@VinceG
Copy link
Owner

VinceG commented Aug 11, 2013

@neara @frgooall this should be fixed now.

@frgooall
Copy link

@VinceG Did you change something recently? I downloaded the wizard last week?

@VinceG
Copy link
Owner

VinceG commented Aug 12, 2013

@frgooall updated today.

@frgooall
Copy link

Last question...I have the wizard in a modal dialog, will this affect the next, pervious, etc.. buttons with validations? The example references (a href = "#"), but this closes the modal window and open the parent page... (a href="javascript:;") works?

Thanks again for all your work, it is appreciated!!!

@VinceG
Copy link
Owner

VinceG commented Aug 12, 2013

@frgooall Have no idea you'll have to test it.

@frgooall
Copy link

Okay...going to test it now! Keeping my fingers crossed...this has been so frustrating, without your wizard, I'd really be lost. Take care!

@narangrishab
Copy link

@scottyc Your solution seems to work only for the first tab but it fails on the subsequent tabs.

On the second tab, when I enter the inputs, it still shows enter the fields and doesn't move to the next tab

onNext: function (tab, navigation, index) {

                            var isValid = false;    
                            var hadError = false;
                            var tabs = $(".tab-pane");
                            var currentTab = tabs[index - 1];
                            var inputs = $(":input, select");
                            var stepElements = $(currentTab).find(inputs);
                            console.log(stepElements);
                            var count = stepElements.length;
                            if (count <= 0) {
                                return true;
                            }
                            $(stepElements).each(function (idx) {
                                isValid = $(document.forms[0]).validate().element($(this));
                                if (!isValid) { hadError = true; }
                            });

                            if (hadError == false) {

                                if (index == navigation.find('li').length) {
                                    $("form").submit();
                                }

                            }

                            return !hadError;
                    },

$('#createEventForm').validate({

       ignore: ":hidden",
       rules: {

            eventName : {
                required: true,
                minlength: 3
            },
            startDate:
            {
                required: true
            },
            endDate:
            {
                required: true
            },
            startTime:
            {
                required: true
            },
            endTime:
            {
                required: true
            },
            category:
            {
                required: true,
                min:1
            },
            addressMap:
            {
                required: true
            },
            address:
            {
                required: true
            },
            city:
            {
                required: true
            },
            state:
            {
                required: true
            },
            country:
            {
                required: true
            },
            phoneNumber:
            {
                required: true
            }

       },

       messages:
       {
            category: { min: "Select a valid category" }
       },


       submitHandler: function (form) {

            url = $("#createEventForm").attr("action");
            console.log($("#createEventForm").serialize());
            var data = new FormData(document.forms.namedItem("createEventForm"));

            $(".btn").attr("disabled", true);

            $.ajax({
                type: 'POST',
                url: url,
                data: data,
                contentType: false,
                processData: false,
                success : function(data){

                    $(".btn").attr("disabled", false);

                    data = $.parseJSON(data);   

                    if(data.code == 200)
                    {
                        $("#errors").text(''); 
                        $("#errors").show();
                        $("#errors").append(data.message);
                    }
                    else
                    {
                        $("#errors").text(''); //TO NULLIFY PREVIOUS ERRORS
                        $.each(data.message,function(key1,value1)
                        {       
                            $.each(value1, function(key2, value2){
                            $("#errors").append(value2+"<br>"); 
                            $("#errors").show();    
                            });
                        });

                    }

                }   
            })
       }
   });

@andrew-za
Copy link

andrew-za commented Nov 29, 2016

With jQuery you can loop through all visible elements and check their values. I have a function which I run in the "onNext" option:

function checkinputs() {
        var unfilled = 0;
        $('input,textarea,select').filter('[checkme]:visible').each(function(){
            unfilled = 0;
            if (($(this).is(':radio') || $(this).is(':checkbox'))
                    && !$('input[name="'+$(this).attr('name')+'"]:checked').val()) {
                alert('Please checkbox');
                unfilled = 1;
            } else if(!$(this).val()) {
                alert('Please fill in');
                unfilled = 1;
            }
        });
        return unfilled;
    }

@Ocoolsanni
Copy link

Hey @scottyc and @neara hope you got what you were looking for today I had the same issue but this link saved me a lot http://formvalidation.io/examples/bootstrap-wizard/ someone can try this hope it helps

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants