1

I have a form spread over two tabs, I would like to color the tab header red, if the containing tab contains any fields with an error.

I got it pretty much working in this --> fiddle <--. Put a value into the field and you will see how the red tab header disappears. But if you delete your entry so that the error validation kicks in right away, the tab doesn't return to red color.

By the look of it the function invalid-form.validate doesn't hit when an error validation throws for a second time, unless I am hooking into the wrong event.

I am literally running out of events I could hook it into, any idea where to put it? :)

function mark_tab_header_error(form, element, is_error){
    var id = $(form).find(element).closest('.tab-pane').attr('id');
    $(form).find(element).closest('.tabbable').find('.tab_header').each(function(index, value){
        if($(this).attr('href') == '#' + id){
            if(is_error)
                $(this).css({color: 'red'});
            else
                $(this).removeAttr('style');            
        }                   
    }); 
}

$(document).ready(function () {

  var validator = validation_rules('#myform');
  validator.form();

  function validation_rules(form) {

    $.validator.addClassRules("fillone", {
      require_from_group: [1, ".fillone"]
    });

    var validator = $(form).bind("invalid-form.validate",  
            function() { 
                if(validator.numberOfInvalids() > 0)
                    mark_tab_header_error(form, validator.lastElement, true);                           
            }).validate({    
      errorPlacement: function (error, element) {
        var field_error = $(form).find('#id_' + element.attr('name')).siblings('.field_error');
        if (field_error.length > 0) {
          error.appendTo(field_error);
        }

        $(field_error).show();
      },
      invalidHandler: function () {
        $("#validation_summary").text(validator.numberOfInvalids() + " field(s) are invalid");
      },
      errorContainer: "#validation_summary",
      success: function(){
                    mark_tab_header_error(form, validator.lastElement, false);
              }

    });
    return validator;
  }

});
Houman
  • 64,245
  • 87
  • 278
  • 460
  • 1
    sorry to say, but this code is a mess ! structure it better, why one function before the doc ready, then one whithin the doc ready, then this var validator in the scope of the doc then again in the scope of the validation_rules is not going to help you to get anywhere... – mikakun Jan 10 '13 at 15:45
  • I have now a new fiddle with clean up. http://jsfiddle.net/houmie/Nf8xY/9/ – Houman Jan 10 '13 at 16:02
  • Never mind, I found it. Typically, `.validate()` is called _once_ within DOM ready to initialized the form (one time), not within another function. – Sparky Jan 10 '13 at 16:02
  • @Sparky within document ready it is getting auto validated by `validator.form();` P.S I see what you mean. I will correct this in future. – Houman Jan 10 '13 at 16:03
  • `.validate()` is for _initialization_... **one** time... when the page first loads. There are other methods, like `.valid()`, that can be used after initialization to test the form. This is the root of all your headaches and why your code is growing verbose very quickly. It's likely also why nothing behaves as expected. – Sparky Jan 10 '13 at 16:07
  • @Sparky, I just had a full revision on my code. In this updated fiddle http://jsfiddle.net/houmie/Nf8xY/10/ I am clearly running `.validate()` only once in the `document.ready()`. Every keystroke is afterwards tested right away on spot without calling `.valid()`. Do you see any problem with this fiddle? – Houman Jan 10 '13 at 20:28
  • I don't have the time to fully study what you're doing in there but it seems a LOT more verbose than it probably needs to be. – Sparky Jan 10 '13 at 20:35
  • Alright no worries. I have followed the documentation, don't understand what makes you say the code is verbose. We just leave it by that I guess. Because that doesn't help me to see your point. :) – Houman Jan 10 '13 at 21:20

1 Answers1

2

I'm not an expert but I think I've achieved what you are trying to do : forked fiddle

Basically, I've just added this :

$.validator.addMethod("require_from_group", function(value, element, options) {
  var validOrNot = $(".fillone").filter(function() {
     // Each field is kept if it has a value
     return $(this).val();
     // Set to true if there are enough, else to false
  }).length >= 1;

  mark_tab_header_error(form, validator.lastElement, !validOrNot);

  if(!$(element).data('being_validated')) {
    var fields = $(".fillone", element.form);
    fields.data('being_validated', true);
    // .valid() means "validate using all applicable rules" (which 
    // includes this one)
    fields.valid();
    fields.data('being_validated', false);
  }  
  return validOrNot;
}); 

Thanks to this wonderful answer : jQuery Validate - require at least one field in a group to be filled

I'm really not a JavaScript expert, don't hesitate to let me know if it's a bad idea...

Update

Following your comment, I was able to make other validation work : http://jsfiddle.net/PsaJY/3/

I had to do two things :

  • Change the success handler that update the tabs : the error condition should be validator.numberOfInvalids() > 0 instead of false since from what I understand, this handler is called each times a field transtion from error to success states ;
  • Force the validation of the whole form by binding onfocusout and onkeyup events.
Community
  • 1
  • 1
Y__
  • 1,687
  • 2
  • 11
  • 23
  • +1 Thank you for your solution and your effort. It is interesting since it seems to work, but because its bound to the group, any other field validation would break the concept as you see in this fiddle: http://jsfiddle.net/houmie/PsaJY/2/ – Houman Jan 10 '13 at 21:31