I have a PHP data entry page using a Bootstrap Wizard, and now am adding some data validation with jQuery Validate.

I have got the basic <input> type fields to work properly, simply with "required" attribute.

But the last 9 tabs of the wizard are "btn-groups" which are not input types, so dont have this functionality. To get around a previous issue (and something that seems quite common to be honest) I added a "hidden" input field, and when a btn-group is changed, it sets the value of the hidden field.

But I am unable to perform validation against either the btn-groups or the hidden fields.

I saw the first solution to the following thread:

Similar Issue

This seems perfect. However when I plug it into my site, I cannot get the wizard to move from the page before of the wizard (i.e. tab 1) where the first hidden field exists (i.e. tab 2), if i dont pre-set the initial value (which then breaks the validation test!).

Currently, the code looks like below. In the first score tab, "hole1score", I have removed the 'value="0"' and added "required", so it gets the validation. All other tabs have the original syntax with pre-set the value to 0. If I can get past this page in the wizard, I will apply it to all.

<head>
	<!-- THERE IS SOME MORE CODE ABOVE, BUT JUST THE USUAL IMPORTING FILES -->
	
	<!-- Include jQuery Validate -->
	<script src="../js/jquery.validate.min.js"></script>
	
	<!-- Include Bootstrap Wizard -->
	<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap-wizard/1.2/jquery.bootstrap.wizard.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js"></script>
	<script>
		$(document).ready(function() {
			var $validator = $("#entry_form").validate({
			  ignore: [],
			  rules: {
				firstname: {
				  required: true,
				}
			  },
			  messages: {
			  	hcap: "A number is required"
			  }
			});	
			
			$('#rootwizard').bootstrapWizard({
				'tabClass': 'nav nav-pills',
				'onNext': function(tab, navigation, index) {
					//if(index>=2) {
					//	//alert($('#hole1score').val());
					//}
					
					var $valid = $("#entry_form").valid();
					if(!$valid) {
						$validator.focusInvalid();
						return false;
					}
				}
			});

			
			
			$('#rootwizard').bootstrapWizard({onTabShow: function(tab, navigation, index) {
				var $total = navigation.find('li').length;
				var $current = index+1;
				var $percent = ($current/$total) * 100;
		
				$('#rootwizard .progress-bar').css({width:$percent+'%'});
		
				// If it's the last tab then hide the last button and show the finish instead
				if($current >= $total) {
					$('#rootwizard').find('.pager .next').hide();
					$('#rootwizard').find('.pager .finish').show();
					$('#rootwizard').find('.pager .finish').removeClass('disabled');
				} else {
					$('#rootwizard').find('.pager .next').show();
					$('#rootwizard').find('.pager .finish').hide();
				}
			}});
					
			$(".btn-group :input").change(function() {
				$('input[name="' + $(this).parent().parent().attr('id') + '"]').val($(this).val());
			}); 
		});
	</script>
	<script>
	  function selectPlayer(myForm)
	  {
		var jplayerid = myForm.playerlist.options[myForm.playerlist.selectedIndex].value;
		var jplayername = myForm.playerlist.options[myForm.playerlist.selectedIndex].text;
		var jplayernames = jplayername.split(" ");
		myForm.firstname.value = jplayernames[0];
		myForm.lastname.value = jplayernames[1];
	  }
	</script>
</head>

<body>

			<div id="rootwizard">
				
				<div class="row">
					<div class="col-xs-12 col-sm-12">
						<div class="navbar">
							<div class="navbar-inner">
								<ul>
									<li><a href="#tab1" data-toggle="tab">Info</a></li>
									<li><a href="#tab2" data-toggle="tab">1st</a></li>
									<li><a href="#tab3" data-toggle="tab">2nd</a></li>
									<li><a href="#tab4" data-toggle="tab">3rd</a></li>
									<li><a href="#tab5" data-toggle="tab">4th</a></li>
									<li><a href="#tab6" data-toggle="tab">5th</a></li>
									<li><a href="#tab7" data-toggle="tab">6th</a></li>
									<li><a href="#tab8" data-toggle="tab">7th</a></li>
									<li><a href="#tab9" data-toggle="tab">8th</a></li>
									<li><a href="#tab10" data-toggle="tab">9th</a></li>
								</ul>
							</div>
						</div>
					</div>
				</div>
				
				<div class="row">
					<div class="col-xs-12">
						<div id="bar" class="progress progress-striped active">
							<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div>
						</div>	
					</div>				
				</div>
				
				<form action="" method="post" class="form" role="form" name="entry_form" id="entry_form" autcomplete="on">
					<div class="tab-content">
						<div class="tab-pane" id="tab1">
							
							<div class="row">
								<div class="col-xs-12">
									<label for="">Name</label>
								</div>
							</div>
							
							<div class="row">
            					<div class="col-xs-12 col-sm-6 col-md-4">
									<select class="form-control" name="playerlist" id="playerlist" onchange="selectPlayer(this.form)">
										<option value="" selected>Select Name or Type New Name</option>
										<?php
											$player_list = get_players();
											echo $player_list;
										?>
									</select>
									<br>                					
            					</div>
            				</div>
            				
            				<div class="row">
								<div class="col-xs-6 col-sm-3 col-md-2">
									<input class="form-control" id="firstname" name="firstname" type="text" required />
								</div>
								<div class="col-xs-6 col-sm-3 col-md-2">
									<input class="form-control" id="lastname" name="lastname" type="text" required />
								</div>
							</div>

							<div class="row">
								<div class="col-xs-12">
									<br>
									<label for="">HCap and Nine</label>
								</div>
							</div>

							<div class="row">
								<div class="col-xs-6 col-sm-3 col-md-2">
									<input class="form-control" name="hcap" placeholder="HCap" type="number" required />
								</div>
								<div class="col-xs-6 col-sm-3 col-md-2">
									<select name="nine" class="form-control" required>
										<option value="">Select Nine</option>
										<option value="1">Low</option>
										<option value="2">Middle</option>
										<option value="3">High</option>
									</select>
								</div>
							</div>
							
							<div class="row">
								<div class="col-xs-12">
									<br>
									<label for="">Date Played</label>
								</div>
							</div>

							<div class="row">
								<div class="col-xs-12 col-sm-6 col-md-4">
									<div class="col-xs-4">
										<select class="form-control" name="dateday">
											<?php
												for ($x = 1; $x <= 31; $x++) {
													if ($todayday==$x){
														$dynday .= '<option value='.$x.' selected>'.$x.'</option>';
													} else {
														$dynday .= '<option value='.$x.'>'.$x.'</option>';
													}
												;
												}
												echo $dynday;
											?>
										</select>
									</div>
									<div class="col-xs-4">
										<select class="form-control" name="datemonth">
											<?php
												for ($x = 1; $x <= 12; $x++) {
													if ($todaymonth==$x){
														$dynmonth .= '<option value='.$x.' selected>'.$x.'</option>';
													} else {
														$dynmonth .= '<option value='.$x.'>'.$x.'</option>';
													}
												};
												echo $dynmonth;
											?>
										</select>
									</div>
									<div class="col-xs-4">
										<select class="form-control" name="dateyear">
											<?php
												$dynyear = '<option value='.$todayyear.' selected>'.$todayyear.'</option>';
												echo $dynyear;
											?>
										</select>
										<br>
									</div>
								</div>
							</div>								
							
						</div>
						
						<div class="tab-pane" id="tab2">
							
							<div class="row">
								<div class="col-xs-12">
									<label for="">HOLE 1 Gross Score</label>										
								</div>
							</div>
							
							<div class="row">
								<div class="col-xs-12 col-sm-9">
									<div class="btn-group btn-group-justified" data-toggle="buttons" id="hole1score">
										<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="0"> Blob
										</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="2">2
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="3">3
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="4">4
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="5">5
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="6">6
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="7">7
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="8">8
									  	</label>
									  	<input type="hidden" name="hole1score" required>
									</div>
								
								</div>								
							</div>
						</div>

						<div class="tab-pane" id="tab3">
							
							<div class="row">
								<div class="col-xs-12">
									<label for="">HOLE 2 Gross Score</label>										
								</div>
							</div>
							
							<div class="row">
								<div class="col-xs-12 col-sm-9">
									<div class="btn-group btn-group-justified" data-toggle="buttons" id="hole2score">
										<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="0"> Blob
										</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="2">2
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="3">3
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="4">4
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="5">5
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="6">6
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="7">7
									  	</label>
									  	<label class="btn btn-primary btn-responsive">
											<input type="radio" autocomplete="off" value="8">8
									  	</label>
									  	<input type="hidden" name="hole2score" value="0">
									</div>
								
								</div>								
							</div>
						</div>

							<div class="row">
								<br>
								<div class="col-xs-4 col-xs-offset-8 col-sm-2 col-sm-offset-7 col-md-offset-8">
									<button name="submit" class="btn btn-responsive btn-success" type="submit">Submit</button>								
								</div>
							</div>
						</div>
						
						<div class="row">
							<div class="col-xs-12">
								<ul class="pager wizard">
									<li class="previous first"><a href="javascript:;">First</a></li>
									<li class="previous first" style="display:none;"><a href="#">First</a></li>
									<li class="previous"><a href="#">Previous</a></li>
									<li class="next last" style="display:none;"><a href="#">Last</a></li>
									<li class="next"><a href="#">Next</a></li>
									<li class="next finish" style="display:none;"><a href="javascript:;">Finish</a></li>
								</ul>								
							</div>
						</div>							
						
					</div>
				</form>


			</div>


</body>

Any help would be appreciated

The answer you linked to tried to solve the problem by listening for changes on buttons and populating a hidden field so that jQuery Validate had something to, well, validate. However, there's a simpler way to do this with native features that already exist in the library.

Bootstrap's button group is just a css wrapper for input[type=radio] to make it look pretty, and you can easily require radio buttons like this:

<!-- language: lang-js -->
myRadioGroupName: { required: true}

or this:

<!-- language: lang-html -->
<input type="radio" name="myRadioGroupName" value="0" required>  1
<input type="radio" name="myRadioGroupName" value="1" > 2
<input type="radio" name="myRadioGroupName" value="2" > 3

Note: Make sure you name all radio button groups. This ensures the radio buttons work properly in all browsers and that they post back a value with the form correctly.

Now jQuery Validate will automatically provide field validation messages for your group, but you'll probably want to move them outside of the radio button group. You can customize their placement like this:

<!-- language: lang-html -->
<label for="myRadioGroupName" generated="true" class="error"></label>

Here's a demo in Stack Snippets

<!-- begin snippet: js hide: false --> <!-- language: lang-js -->
$(function() { 

  $("#test-form").validate({  
    ignore: [],
    rules: {
      first_name: { 
        required: true
      },
      hole1score: {
        required: true
      }
    }
  });
});
<!-- language: lang-html -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

<form id="test-form" action="post.php">
  <input type="text" name="first_name" class="form-control" required /><br/>
  
  <div class="btn-group btn-group-justified" data-toggle="buttons" id="hole1score">
    <label class="btn btn-primary btn-responsive">
      <input type="radio" autocomplete="off" name="hole1score" value="1" >1
    </label>
    <label class="btn btn-primary btn-responsive">
      <input type="radio" autocomplete="off" name="hole1score" value="2" >2
    </label>
    <label class="btn btn-primary btn-responsive">
      <input type="radio" autocomplete="off" name="hole1score" value="3">3
    </label>
  </div>

  <label for="hole1score" generated="true" class="error"></label><br/>
  
  <input type="submit" />
</form>
<!-- end snippet -->