title: Bootstrap formvalidation.io trying to require one field or the other
body: <p>I have recently purchased and am using Bootstrap FormValidation from <a href="http://formvalidation.io/">http://formvalidation.io/</a> and using the example on <a href="http://formvalidation.io/examples/requiring-at-least-one-field/">http://formvalidation.io/examples/requiring-at-least-one-field/</a> I am trying to set up my for the require EITHER an email or a phone number but I am not able to get the example to work correctly.  No matter what I do I see an error message saying "You must enter at least one contact method" only under the Primary Email field.</p>
  
  <p>If the FULL code would be helpful I can post but here are the relevant code snippets.</p>
  
  <pre><code>&lt;div class="form-group"&gt;
      &lt;label class="control-label" for="primaryEmail"&gt;Primary Email&lt;/label&gt;
      &lt;input type="text" class="form-control contactMethod" id="primaryEmail" 
                                 name="primaryEmail" value="" placeholder="Enter email"&gt;
  &lt;/div&gt;
  &lt;div class="form-group"&gt;
      &lt;label class="control-label" for="cPhone"&gt;Cell Phone&lt;/label&gt;
      &lt;input type="text" class="form-control contactMethod" id="cPhone" name="cPhone" 
              value="" placeholder="Enter cell phone"&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>Validation section of the javascript</p>
  
  <pre><code>$('#form').formValidation({
              framework: 'bootstrap',
              icon: {
                  valid: 'glyphicon glyphicon-ok',
                  invalid: 'glyphicon glyphicon-remove',
                  validating: 'glyphicon glyphicon-refresh'
              },
              fields: {
  
                  cPhone: {
                      validators: {
                          phone: {
                              country: 'country',
                              message: 'The value is not valid %s phone number'
                          }
                      }
                  },
                  primaryEmail: {
                      validators: {
                          emailAddress: {
                              message: 'The value is not a valid email address'
                          }
                      }
                  },
                  secondaryEmail: {
                      validators: {
                          emailAddress: {
                              message: 'The value is not a valid email address'
                          }
                      }
                  },
                  wPhone: {
                      validators: {
                          phone: {
                              country: 'country',
                              message: 'The value is not valid %s phone number'
                          }
                      }
                  },
                  contact : {
                      selector: '.contactMethod',
                      validators: {
                          callback: {
                              message: 'You must enter at least one contact method',
                              callback: function(value, validator, $field) {
                                  var isEmpty = true,
                                  // Get the list of fields
                                  $fields = validator.getFieldElements('contact');
                                  console.log($fields);
                                  for (var i = 0; i &lt; $fields.length; i++) {
                                      if ($fields.eq(i).val() !== '') {
                                          isEmpty = false;
                                          break;
                                      }
                                  }
  
                                  if (!isEmpty) {
                // Update the status of callback validator for all fields
                validator.updateStatus('contact', validator.STATUS_VALID, 'callback');
                                      return true;
                                  }
  
                                  return false;
                              }
                          }
                      }
                  }
              }
          });
  </code></pre>
  
  <p>In the exmaple the line <code>$fields = validator.getFieldElements('cm');</code> has <strong>cm</strong> replaced with <strong>email</strong> but it did appear to be anything but an arbitrary label. But it maybe more than a label that matches the <code>validator.updateStatus('cm', validator.STATUS_VALID, 'callback');</code> line.  <em>cm has been changed to contact</em></p>
  
  <p>All other validations seem to be working on the page.</p>
  
  <p>UPDATE: </p>
  
  <p>if I dump <code>$fields</code> to the console right after <code>$fields = validator.getFieldElements('cm');</code> I get <code>"input=([name="primaryEmail"])"</code> I would have thought it would have been an object with both primaryEmail and cPhone.</p>
  
  <p><strong>UPDATE 5-18-15</strong>
  first the HTML then the scripts.  I have made things even more difficult by adding a thrid option into the mix but the use can use a cell phone, work phone or primary email as a contact method one one is required.</p>
  
  <pre><code>&lt;div class="form-group"&gt;
      &lt;label class="control-label" for="primaryEmail"&gt;Primary Email &lt;i class="fa fa-asterisk text-warning"&gt;&lt;/i&gt;&lt;/label&gt;
      &lt;input type="text" class="form-control contactMethod" id="primaryEmail" name="primaryEmail" value="" placeholder="Enter email" data-fv-field="contactMethod"&gt;
  &lt;/div&gt;
  &lt;div class="form-group"&gt;
      &lt;label class="control-label phoneMask" for="cPhone"&gt;Cell Phone &lt;i class="fa fa-asterisk text-warning"&gt;&lt;/i&gt;&lt;/label&gt;
      &lt;input type="text" class="form-control contactMethod" id="cPhone" name="cPhone" value="" placeholder="Enter cell phone" data-fv-field="contactMethod"&gt;
  &lt;/div&gt;
  &lt;div class="form-group"&gt;
      &lt;label class="control-label phoneMask" for="wPhone"&gt;Work Phone &lt;i class="fa fa-asterisk text-warning"&gt;&lt;/i&gt;&lt;/label&gt;
      &lt;input type="text" class="form-control contactMethod" id="wPhone" name="wPhone" value="" placeholder="Enter work phone" data-fv-field="contactMethod"&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>I have tried several scripts :</strong> </p>
  
  <p>Here is the one that most closely resembled the example on <a href="http://formvalidation.io/examples/requiring-at-least-one-field/">http://formvalidation.io/examples/requiring-at-least-one-field/</a></p>
  
  <pre><code>$('#leadForm').formValidation({
      framework: 'bootstrap',
      icon: {
          valid: 'glyphicon glyphicon-ok',
          invalid: 'glyphicon glyphicon-remove',
          validating: 'glyphicon glyphicon-refresh'
      },
      fields: {
          fName: {
              validators: {
                  notEmpty: {
                      message: 'The first name is required'
                  },
                  stringLength: {
                      min: 2,
                      max: 30,
                      message: 'The first name must be more than 2 and less than 30 characters long'
                  }
              }
          },
          lName: {
              validators: {
                  notEmpty: {
                      message: 'The last name is required'
                  },
                  stringLength: {
                      min: 2,
                      max: 30,
                      message: 'The last name must be more than 2 and less than 30 characters long'
                  }
              }
          },
          secondaryEmail: {
              validators: {
                  emailAddress: {
                      message: 'The value is not a valid email address'
                  }
              }
          },
          contactMethod: {
              selector: '.contactMethod',
              validators: {
                  callback:  function(value, validator, $field) {
                          var isEmpty = true,
                              isValid = false,
                              returnIsValid = false,
                              // Get the list of fields
                              $fields = validator.getFieldElements('contactMethod'),
                              fv = $('#leadForm').data('formValidation');
                          for (var i = 0; i &lt; $fields.length; i++) {
                              thisField = $fields[i].id;
                              // trim value of field
                              thisVal = jQuery.trim($('#'+thisField).val());
  
                              if(thisVal.length == 0){
                                 console.log('empty '+thisField);
                                  fv.updateStatus(thisField, 'INVALID', 'callback').updateMessage(thisField,validator,'test');
                              } else {
                                  if(thisField == 'cPhone' || thisField == 'wPhone'){
                                      console.log('validating '+thisField);
                                  } else if(thisField == 'primaryEmail'){
                                      console.log('validating '+thisField);
                                  }
                              }
  
  
  
                              if ($fields.eq(i).val() !== '') {
                                  isEmpty = false;
                                  break;
                              }
                          }
  
  
                          if (!isEmpty) {
                              // Update the status of callback validator for all fields
                              validator.updateStatus('contactMethod', validator.STATUS_VALID, 'callback');
                              returnIsValid = false;
                          } else {
  
                          }
                          return returnIsValid;
                  }
              }
          }
      }
  
  }).on('success.form.fv', function(e) {
      e.preventDefault();
      var $form = $(e.target),
          fv    = $form.data('formValidation');
          // console.log($form.serialize());
          // console.log(fv);
      $.ajax({
          type: 'post',
          url: 'api/add.jsp?surveyId='+cfg['lead.surveyID'],
          data: $form.serialize(),
          dataType: 'json',
          async: false,
          success: function(result){
              console.log(result);
  
              }
          } 
      });     
  });
  </code></pre>
  
  <p>This one more closely resembles what @Béranger had suggested.  It actually comes very close but since so much of it is on the keyup it isn't triggered on the click of the submit button.  I have tried adding.</p>
  
  <pre><code>$('#leadForm').formValidation({
      framework: 'bootstrap',
      icon: {
          valid: 'glyphicon glyphicon-ok',
          invalid: 'glyphicon glyphicon-remove',
          validating: 'glyphicon glyphicon-refresh'
      },
      fields: {
          primaryEmail: {
              validators: {
                  notEmpty: {
                      message: 'You must include at least one contact method'
                  },
                  emailAddress: {
                      message: 'The value is not a valid email address'
                  }
              }
          },
          cPhone: {
              validators: {
                  notEmpty: {
                      message: 'You must include at least one contact method'
                  },
                  phone: {
                      country: 'country',
                      message: 'The value is not valid %s phone number'
                  }
              }
          },
          wPhone: {
              validators: {
                  notEmpty: {
                      message: 'You must include at least one contact method'
                  },
                  phone: {
                      country: 'country',
                      message: 'The value is not valid %s phone number'
                  }
              }
          }
      }
  })
  .on('keyup', '[name="primaryEmail"], [name="cPhone"], [name="wPhone"]', function(e) {
      var cPhoneIsEmpty = jQuery.trim($('#leadForm').find('[name="cPhone"]').val()) === '',
          wPhoneIsEmpty = jQuery.trim($('#leadForm').find('[name="wPhone"]').val()) === '',
          primaryEmailIsEmpty = jQuery.trim($('#leadForm').find('[name="primaryEmail"]').val()) === '',
          fv = $('#leadForm').data('formValidation');
  
      var cPhoneIsValid = fv.isValidField('cPhone') === true ? true : false;
      var wPhoneIsValid = fv.isValidField('wPhone') === true ? true : false;
      var primaryEmailIsValid = fv.isValidField('primaryEmail') === true ? true : false;
  
      switch ($(this).attr('name')) {
          // User is focusing the primaryEmail field
          case 'primaryEmail':
              fv.enableFieldValidators('cPhone', primaryEmailIsEmpty).revalidateField('cPhone');
              fv.enableFieldValidators('wPhone', primaryEmailIsEmpty).revalidateField('wPhone');
  
              break;
  
          // User is focusing the cPhone field
         case 'cPhone':
              fv.enableFieldValidators('primaryEmail', cPhoneIsEmpty).revalidateField('primaryEmail');
              fv.enableFieldValidators('wPhone', cPhoneIsEmpty).revalidateField('wPhone');
  
              break;
  
          // User is focusing the cPhone field
         case 'wPhone':
              fv.enableFieldValidators('primaryEmail', wPhoneIsEmpty).revalidateField('primaryEmail');
              fv.enableFieldValidators('cPhone', wPhoneIsEmpty).revalidateField('cPhone');
  
              break;
  
          default:
              break;
      }
  
      // if( (cPhoneIsValid || wPhoneIsValid || primaryEmailIsValid)){
      //  fv.enableFieldValidators('primaryEmail', false, 'notEmpty').revalidateField('primaryEmail');
      //  fv.enableFieldValidators('cPhone', false, 'notEmpty').revalidateField('cPhone');
      //  fv.enableFieldValidators('wPhone', false, 'notEmpty').revalidateField('cPhone');
      // } else {
      //  fv.enableFieldValidators('primaryEmail', true).revalidateField('primaryEmail');
      //  fv.enableFieldValidators('cPhone', true).revalidateField('cPhone');
      //  fv.enableFieldValidators('wPhone', true).revalidateField('cPhone');
      // }
  
      // fv.enableFieldValidators('primaryEmail', true);
      // fv.enableFieldValidators('cPhone', true);
      // fv.enableFieldValidators('wPhone', true);
  
  }).on('success.form.fv', function(e) {
      e.preventDefault();
      // console.log('submit here');
      var $form = $(e.target),
          fv    = $form.data('formValidation');
          // console.log($form.serialize());
          // console.log(fv);
      $.ajax({
          type: 'post',
          url: 'api/add.jsp?surveyId='+cfg['lead.surveyID'],
          data: $form.serialize(),
          dataType: 'json',
          async: false,
          success: function(result){
              console.log(result);
          } 
      });     
  });
  </code></pre>