0

I've created a wizard using BootstrapWizard, but I need to convalidate the input before saving them. At the moment when I fill the first tab, I can't actually go to the next tab 'cause the valid() method will return false.

The result of the valid() method is correct because there are other inputs on the others tab, but I doesn't have any access to that tab control, because I'm on the first tab.

For clarify I have created a fiddler

essentially when you fill the first tab, and then click on the next button, you will reiceve false from valid(), 'cause the required control which exists in the next tab is not filled, but I can't fill it.

Is there a way to fix this?

Code:

<div class="wizard-container">
  <form id="member-form" method="get" action="" class="form-horizontal">
    <div class="card card-wizard card-wizard-borderless active" data-color="rose">
      <div class="wizard-navigation">
        <ul>
          <li><a href="#tab1" data-toggle="tab">First</a></li>
          <li><a href="#tab2" data-toggle="tab">Second</a></li>
          <li><a href="#tab3" data-toggle="tab">Third</a></li>
        </ul>
      </div>
      <div class="tab-content">
        <div class="tab-pane active" id="tab1">
          <div class="control-group">
            <label class="control-label" for="email">Email</label>
            <div class="controls">
              <input type="text" id="emailfield" name="first_name" class="control-form">
            </div>
          </div>

          <div class="control-group">
            <label class="control-label" for="name">Name</label>
            <div class="controls">
              <input type="text" id="namefield" name="last_name" class="control-form">
            </div>
          </div>
        </div>
        <div class="tab-pane" id="tab2">
          <div class="control-group">
            <label class="control-label" for="url">URL</label>
            <div class="controls">
              <input type="text" id="urlfield" name="state" class="control-form">
            </div>
          </div>
        </div>
        <div class="tab-pane" id="tab3">
          3
        </div>
        <div class="card-footer">
          <div class="mr-auto">
            <input type="button" class="btn btn-previous btn-fill btn-default btn-wd disabled" name="previous" value="previous">
          </div>
          <div class="ml-auto">
            <input type="button" class="btn btn-next btn-fill btn-rose btn-wd" name="next" value="next">
            <input type="button" id="save-member" class="btn btn-finish btn-fill btn-rose btn-wd" name="finish" value="save" style="display: none;">
          </div>
          <div class="clearfix"></div>
        </div>
      </div>
    </div>
  </form>
</div>

$(document).ready(function() {
    $('#member-form').validate({
    ignore: '.ignore',
    rules: {
      first_name: "required",
      last_name: "required",
      state: "required"
    }
  });

  $('.card-wizard').bootstrapWizard({
    'tabClass': 'nav nav-pills',
    'nextSelector': '.btn-next',
    'previousSelector': '.btn-previous',

    onNext: function(tab, navigation, index) {

      let valid = $('#member-form').valid();
      if (!valid) {
        return false;
      }
    }
  });
});
sfarzoso
  • 1,356
  • 2
  • 24
  • 65

1 Answers1

1

You're getting that because jQuery validate plugin tries to validate all the inputs you have given including the URL input which you can't reach so you will always end up with a false result preventing you from reaching the next tab where that URL input is.

jQuery validate plugin provides a way to individually check each input instead of checking the whole form's inputs all at once, more infos here.

So going from there, I revamped some of your code to make it work as you'd expect, I commented some lines to explain how it works :

$(document).ready(function() {
  var validator = $('#member-form').validate({
    ignore: '.ignore',
    rules: {
      first_name: "required",
      last_name: "required",
      state: "required"
    }
  });

  $('.card-wizard').bootstrapWizard({
    'tabClass': 'nav nav-pills',
    'nextSelector': '.btn-next',
    'previousSelector': '.btn-previous',

    onNext: function(tab, navigation, index) {
      let tab_id = tab.children().attr('href'); //we select the current's tab ID
      let inputs = $(tab_id).find('input'); //we fetch the current's tab inputs
      var fail = false; //we initalize fail validation variable
      //we loop through each of the inputs to validate them
      $(inputs).each(function(key, val) {
        if (!validator.element(val)) {
          fail = true;
        }
      });

      //if fail equals true it means at least one input failed to get validated thus we stop the script from executing further
      if (fail) {
        return false;
      }
    }
  });
});

Working demo below :

$(document).ready(function() {
  var validator = $('#member-form').validate({
    ignore: '.ignore',
    rules: {
      first_name: "required",
      last_name: "required",
      state: "required"
    }
  });

  $('.card-wizard').bootstrapWizard({
    'tabClass': 'nav nav-pills',
    'nextSelector': '.btn-next',
    'previousSelector': '.btn-previous',

    onNext: function(tab, navigation, index) {
      let tab_id = tab.children().attr('href'); //we select the current's tab ID
      let inputs = $(tab_id).find('input'); //we fetch the current's tab inputs
      var fail = false; //we initalize fail validation variable
      //we loop through each of the inputs to validate them
      $(inputs).each(function(key, val) {
        if (!validator.element(val)) {
          fail = true;
        }
      });

      //if fail equals true it means at least one input failed to get validated thus we stop the script from executing further
      if (fail) {
        return false;
      }
    },
    onTabClick: function(tab, navigation, index, tabIndex) {
      let tab_id = tab.children().attr('href'); //we select the current's tab ID
      let inputs = $(tab_id).find('input'); //we fetch the current's tab inputs
      var fail = false; //we initalize fail validation variable
      //we loop through each of the inputs to validate them
      $(inputs).each(function(key, val) {
        if (!validator.element(val)) {
          fail = true;
        }
      });
      //if the clicked tab is the third one, we check all previous tabs input fields for validation
      if (tabIndex == 2) {
        $('#tab1, #tab2').find('input').each(function(key, val) {
          if (!validator.element(val)) {
            fail = true;
          }
        });
      }
      //if fail equals true it means at least one input failed to get validated thus we stop the script from executing further
      if (fail) {
        return false;
      }
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap-wizard/1.2/jquery.bootstrap.wizard.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.min.js"></script>

<div class="wizard-container">
  <form id="member-form" method="get" action="" class="form-horizontal">
    <div class="card card-wizard card-wizard-borderless active" data-color="rose">
      <div class="wizard-navigation">
        <ul>
          <li><a href="#tab1" data-toggle="tab">First</a></li>
          <li><a href="#tab2" data-toggle="tab">Second</a></li>
          <li><a href="#tab3" data-toggle="tab">Third</a></li>
        </ul>
      </div>
      <div class="tab-content">
        <div class="tab-pane active" id="tab1">
          <div class="control-group">
            <label class="control-label" for="email">Email</label>
            <div class="controls">
              <input type="text" id="emailfield" name="first_name" class="control-form">
            </div>
          </div>

          <div class="control-group">
            <label class="control-label" for="name">Name</label>
            <div class="controls">
              <input type="text" id="namefield" name="last_name" class="control-form">
            </div>
          </div>
        </div>
        <div class="tab-pane" id="tab2">
          <div class="control-group">
            <label class="control-label" for="url">URL</label>
            <div class="controls">
              <input type="text" id="urlfield" name="state" class="control-form">
            </div>
          </div>
        </div>
        <div class="tab-pane" id="tab3">
          3
        </div>
        <div class="card-footer">
          <div class="mr-auto">
            <input type="button" class="btn btn-previous btn-fill btn-default btn-wd disabled" name="previous" value="previous">
          </div>
          <div class="ml-auto">
            <input type="button" class="btn btn-next btn-fill btn-rose btn-wd" name="next" value="next">
            <input type="button" id="save-member" class="btn btn-finish btn-fill btn-rose btn-wd" name="finish" value="save" style="display: none;">
          </div>
          <div class="clearfix"></div>
        </div>
      </div>
    </div>
  </form>
</div>

Hope this helps.

tcj
  • 1,645
  • 4
  • 13
  • 21
  • I appreciated your answer, but why this solution which I found on codepen is working: https://codepen.io/makshh/pen/dOQyqJ?editors=1010 and mine not? what's the difference? – sfarzoso Aug 21 '19 at 17:31
  • Well, after having checked that codepen I noticed the difference is it's not using the `ignore` rule whereas you use it in your code, if you remove the `ignore` line from your code it'll work. – tcj Aug 21 '19 at 18:21
  • @tjc that's weird, and if I have to ignore a field? – sfarzoso Aug 21 '19 at 18:39
  • My code works with the `ignore` statement I guess (haven't tested it but at least it passes the validation). – tcj Aug 21 '19 at 18:40
  • And if you also want it to work on a tab click, copy/paste my code from `onNext` method to `onTabClick` (you must write that new method). – tcj Aug 21 '19 at 18:48
  • I just noticed a bug in your code, infact if I'm on the first tab, and I try to skip the second to go in the third tab, your code doesn't validate the second tab. Could you please fix this? – sfarzoso Aug 22 '19 at 14:09
  • 1
    Yes, in my previous message I was refering to the tab clicking not working because you'd have to write the tab clicking method too so I updated my code accordingly to make it work on tab click. – tcj Aug 22 '19 at 15:40
  • 1
    @tjc nope the bug is still there, if you fill the first tab and then click on the third, you will see that you can skip the tab 2, this is bad 'cause the tab 2 need validation too.. – sfarzoso Aug 22 '19 at 16:32
  • 1
    Got it, hold on few mins I'll fix that. – tcj Aug 22 '19 at 16:37
  • 1
    Bug fixed, check the updated code, I've commented the added line of code. – tcj Aug 22 '19 at 17:15