Search code examples
jqueryjquery-validatetooltipster

jQuery Validation required not clearing tooltipster error message when based on a function


This seemed like something simple, but I am stumped. I have a form and want a field to be required if the value of another field is greater than zero. While the validation actually works and allows me to submit, the error tooltip doesn't clear when I change the value back to zero.

In the fiddle, if the Misc amount is greater than 0, i want the comments to be required, otherwise not required. As I said, the validation works, but the validation message doesn't get cleared.

        jQuery(document).ready(function() {
          //Initialize the tooltips
          jQuery('.tooltip').tooltipster({
            contentAsHTML: true
          });
          jQuery('#frmForm :input').each(function() {
            var tipelement = getTipContainer(this);

            jQuery(tipelement).tooltipster({
              trigger: 'custom',
              onlyOne: false,
              position: 'right',
              multiple: true,
              autoClose: true
            });

          });
          jQuery("#frmForm").validate({
            ignore: [],
            rules: {
              MISCComments: {
                required: function(element) {
                  return jQuery("#MISCAmount").val() > 0;
                }
              }
            },
            messages: {
              MISCComments: "Explain what this payment is for."
            },
            errorPlacement: function(error, element) {
              var $element = jQuery(element),
                tipelement = element,
                errtxt = jQuery(error).text(),
                last_error = '';

              tipelement = getTipContainer(element);

              last_error = jQuery(tipelement).data('last_error');
              jQuery(tipelement).data('last_error', errtxt);
              if (errtxt !== '' && errtxt != last_error) {
                jQuery(tipelement).tooltipster('content', errtxt);
                jQuery(tipelement).tooltipster('show');
              }
            },
            success: function(label, element) {
              var tipelement = getTipContainer(element);
              jQuery(tipelement).tooltipster('hide');
            }
          });

          //this function selects a container for 'group' elements like
          //check box /radio groups
          function getTipContainer(element) {
            var tipelement = element;
            if (jQuery(element).is(":checkbox") || jQuery(element).is(":radio")) {
              tipelement = jQuery(element).parents('.container').get(0);
            }
            return tipelement;
          }
        });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tooltipster/3.3.0/js/jquery.tooltipster.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.validate.js"></script>

<link href="https://cdnjs.cloudflare.com/ajax/libs/tooltipster/3.3.0/css/tooltipster.min.css" rel="stylesheet"/>

<form name="frmForm" id="frmForm" method="post">

  <div class="form-group row">
    <div class="col-md-2">
      CE Vendor Fees
      <input type="hidden" name="CE_VENDORS" id="CE_VENDORS" value="CE_VENDORS">
    </div>
    <div class="col-md-3">
      <input id="CE_VENDORSInvoiceNumber" name="CE_VENDORSInvoiceNumber" type="text" placeholder="Invoice #" class="form-control input-md" style="20px;" value="">
    </div>
    <div class="col-md-3">
      <input id="CE_VENDORSAmount" name="CE_VENDORSAmount" type="text" placeholder="Amount" class="form-control input-md Amounts" value="2.00" style="text-align: right;">
    </div>
  </div>
  <div class="form-group row">
    <div class="col-md-2">

    </div>
    <div class="col-lg-9">
      <input id="CE_VENDORSComments" name="CE_VENDORSComments" type="text" placeholder="Comments" class="form-control input-md" value="">
      <label for="CE_VENDORSComments" class="error"></label>
    </div>
  </div>
  <div class="form-group row">
    <div class="col-md-12">&nbsp;
    </div>
  </div>

  <div class="form-group row">
    <div class="col-md-2">
      Miscellaneous
      <input type="hidden" name="MISC" id="MISC" value="MISC">
    </div>
    <div class="col-md-3">
      <input id="MISCInvoiceNumber" name="MISCInvoiceNumber" type="text" placeholder="Invoice #" class="form-control input-md" style="20px;" value="">
    </div>
    <div class="col-md-3">
      <input id="MISCAmount" name="MISCAmount" type="text" placeholder="Amount" class="form-control input-md Amounts" value="1.00" style="text-align: right;">
    </div>
  </div>
  <div class="form-group row">
    <div class="col-md-2">

    </div>
    <div class="col-lg-9">
      <input id="MISCComments" name="MISCComments" type="text" placeholder="Comments" class="form-control input-md" value="">

    </div>
  </div>
  <button class="button-tooltip" title="Submit details">Submit</button>
</form>

Fiddle here


Solution

  • Since you're dynamically changing the rule, you'll need to programmatically force validation of this field when the value of the dependent field is edited.

    jQuery('[name="MISCAmount"]').on('blur keyup', function() {
        jQuery('[name="MISCComments"]').valid();  // force validation
    });
    

    Also...

    The success function will not re-fire on an "optional" field when this field is blanked out or the rules are changed. This is the root issue. Your field is dynamically changed from required into "optional" and there is no way to force the success function to re-fire for this case.

    The solution is to use the unhighlight function instead of success, which fires every single time a field is evaluated for validity. The following code attaches the show and hide methods to these default functions.

    unhighlight: function(element, errorClass, validClass) {
        $(element).removeClass(errorClass).addClass(validClass).tooltipster('hide');
    },
    highlight: function(element, errorClass, validClass) {
        $(element).addClass(errorClass).removeClass(validClass).tooltipster('show');
    },
    

    DEMO: jsfiddle.net/sk074zwv/9/

    Quoting myself from this other answer:

    "I also replaced the success callback with unhighlight. On "optional" fields, the error message was never removed when the field was subsequently blanked out... this is because the success function does not fire under these circumstances."


    I also recommend that you upgrade to ToolTipster version 4 and rework your code for such. Version 4 contains some new/improved methods such as open and close, which makes a little more sense for toggling tooltips, and works very well with highlight and unhighlight.