1

Jquery validate validates the form fields that are already in the DOM as well as fields that are added dynamically. But if the fields that are NOT dynamically added pass validation, the form submits ignoring the dynamically added fields.

Here is a snapshot: snapshot

Here is my code:

 $('#milestone-form').validate({ // initialize the plugin
        rules: {
            "milestone[]": {
                required: true,
                minlength: 3,
            },
            "deadline[]": {
                required: true,
                minlength: 3,
            },
            "amount[]": {
                required: true,
                minlength: 2,
            },

        },
        submitHandler: function(form) {
              var data = $("#milestone-form").serialize();
                $.ajax({
                    type:"POST",
                    url:"ajax/scripts/crt_ms.php",
                    data:data,
                    success:function(data){ 
                        if(!data){alert("Something went wrong")}else{alert("Success")}
                        $(document).off();
                        },  
                    });
            },
    });
    //Validation End

  $(document).on('click', ".add", function(){
  $(flieds).insertAfter($(this).closest("#fields"));
  $('.field').each(function() {
  $(this).rules('add', {
    required: true,
        });
    });
}); 

$(".save-ms").click(function(){
    if($('#milestone-form').valid()){
        //$("#milestone-form").submit();
        alert("POSTED");
         return false;
    } else { alert("ERROR");}
});

All my <input> elements have a class=".field" attribute.

Also, I noticed one thing that all the dynamic fields do not get a error LABEL instead only have a class to define it as invalid.

I have been trying the whole day to do this but just not happening.

Ikhlak S.
  • 8,578
  • 10
  • 57
  • 77

2 Answers2

2

It is simple. Jquery validate doesn't validate multiple elements with the same name.

So the solution I found is here, originally from here

I just had to add this.

$(document).ready(function(){
$.validator.prototype.checkForm = function () {
            //overriden in a specific page
  this.prepareForm();
  for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) {
      if (this.findByName(elements[i].name).length != undefined && this.findByName(elements[i].name).length > 1) {
          for (var cnt = 0; cnt < this.findByName(elements[i].name).length; cnt++) {
              this.check(this.findByName(elements[i].name)[cnt]);
          }
      } else {
          this.check(elements[i]);
      }
  }
  return this.valid();
},
};
Community
  • 1
  • 1
Ikhlak S.
  • 8,578
  • 10
  • 57
  • 77
  • Okay... Answer works, But I prefer to do it this way, it's a lot cleaner, and please learn to store your search results instead of doing them over and over and over again in several loops. You keep searching through the DOM elements on every iteration multiple times... Take a look at http://kopy.io/J9q3e. By storing the variables and iterating via the jquery method them your validation will be less resource intensive and quicker. – Tschallacka Nov 16 '15 at 07:33
  • ugh, made a mistake I always make in jquery each, forgot that the first argument to a function is the index. My corrected http://kopy.io/TOknh – Tschallacka Nov 16 '15 at 07:53
  • Good logic. But they seems to be a syntax error console says so. Can't seem to find it though – Ikhlak S. Nov 16 '15 at 08:02
  • if you can profide a jsfiddle with your form code I can fix it :-) I just can't be bothered to type up a form and set up the validator and such. I just typed it out how I would make it using the jQuery each method to keep the function clean. I really advice you to learn about variable scope. And the main lesson i wanted to bring is: Don't repeat a search. Search once, store it, then do your stuff on the stored variable. – Tschallacka Nov 16 '15 at 08:09
  • 1
    I made it work :-) https://jsfiddle.net/mdibbets/f4rm0ut6/14/ Had a few errors, but nice code you have there :-) – Tschallacka Nov 16 '15 at 09:06
  • Thanks! :) . Works like a charm. Can you add you solution as a answer since some people don't bother reading comments. – Ikhlak S. Nov 16 '15 at 09:19
0

In your own answer you used a lot of repeated searches through the DOM elements. Per loop iteration you did at least four dom searches, sometimes even just for the simple length variable.

This puts an unecessary load on the browser. Also I'd suggest making use of the native jQuery functions to help you iterate these loops and then use some scopeing to help you store relevenant references, like one to the validator.

Suggested reading:

What is the scope of variables in JavaScript?
Performance of jQuery selectors vs local variables

$.validator.prototype.checkForm = function () {
        //overriden in a specific page
        this.prepareForm();
        // Scoped variable.  
        var that = this;
        $(this.elements).each(function(index,elem) {
            // Search only once. big speed improv
            var seek = that.findByName(elem.name);
            // undefined and 0 is false by default
            if (seek.length && seek.length > 1) {
                seek.each(function(index,duplicate) {
                    // Notice the use the reference that from the outerscope. 
                    // `that` int his case refers to the the validator object.
                    that.check(duplicate);
                });
            }
          else {
              that.check(seek);
          }
       });
    };

$(document).ready(function(){
$('#milestone-form').validate({ // initialize the plugin
 rules: {
  "milestone[]": {
   required: true,
   minlength: 3,
   },
  "deadline[]": {
   required: true,
   minlength: 3,
   },
  "amount[]": {
   required: true,
   minlength: 2,
   },
     
  },
  submitHandler: function(form) {
    var data = $("#milestone-form").serialize();
   $.ajax({
    type:"POST",
    url:"#",
    data:data,
    success:function(data){ 
     if(!data){alert("Something went wrong")};
     $(document).off();
     }, 
    });
  },
 });
    // ===========================================================================
    $.validator.prototype.checkForm = function () {
        //overriden in a specific page
        this.prepareForm();
        // Scoped variable.  
        var that = this;
        $(this.elements).each(function(index,elem) {
            // Search only once. big speed improv
            var seek = that.findByName(elem.name);
            // undefined and 0 is false by default
            if (seek.length && seek.length > 1) {
                seek.each(function(index,duplicate) {
                    // Notice the use the reference that from the outerscope. 
                    // `that` int his case refers to the the validator object.
                    that.check(duplicate);
                });
            }
          else {
              that.check(seek);
          }
       });
    };
    // ===========================================================================
  
    var form= "<div id='fields'> <input type='text' name='milestone[]' placeholder='Milestone'> <input  type='text' name='deadline[]' placeholder='Deadline'> <input type='text' name='amount[]' placeholder='Amount'> <input type='text' name='p[]' value='1' style='display:none;'> <span class='add halflings-icon plus'>+</span> <span class='remove halflings-icon minus'>-</span> </div>"

 $(document).on('click', ".add", function(){
  $(form).insertAfter($(this).closest("#fields"));
  }); 

 $(document).on('click', ".remove", function(){
  $(this).closest('div').remove();
  }); 

 $(".save-ms").click(function(evt){
        evt.preventDefault();
  if($('#milestone-form').valid()){
   alert("POSTED");
         return false;
  } else { alert("All Fields are required");}
 });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.js"></script>
<form method="post" id="milestone-form">
    <div id="fields" style="width:100%;">
        <input type="text" name="milestone[]" placeholder="Milestone">
        <input type="text" name="deadline[]" placeholder="Deadline">
        <input type="text" name="amount[]" placeholder="Amount">
        <input type="text" name="p[]" value="1" style="display:none;">
        <span class="add halflings-icon plus">+</span>
    </div>  
    <input type="submit" name="save-ms" class="btn btn-primary save-ms" value="Create">
</form>
Community
  • 1
  • 1
Tschallacka
  • 27,901
  • 14
  • 88
  • 133