Cannot validate single tab per time

917 Views Asked by At

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;
      }
    }
  });
});
1

There are 1 best solutions below

10
On BEST ANSWER

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.