3

Looking at the documentation here: http://docs.jquery.com/Plugins/Validation/Reference#Fields_with_complex_names_.28brackets.2C_dots.29 the syntax for attaching rules to input arrays is like this:

rules: {
"user[email]": "email",

However in my case the array keys are number values and could have any value, but still I'd like to attach the rule to the fields. I dynamically add input fields with jQuery (key is a global variable):

 $('a#addfield').click(function(e)
 {
    e.preventDefault();
    var data = '<p><input type="file" name="field['+key+']"></p>';
    $('div#inputcontainer').append(data);
 });

Sample HTML output:

<p><input name="field[19]" type="file"></p>
<p><input name="field[22]" type="file"></p>
<p><input name="field[25]" type="file"></p>

I have tried defining the rules like this:

rules: 
{
   'field[]': {
         required: true,
         extension: "pdf|doc|docx"
    }
}

(taken from this answer: jquery validate add rules for an array input EDIT: This suggested way of setting rules with 'field[]' is not working with the validation plugin. See answer and comments below. )

But there is no validation error when I try to add other filetypes... Any suggestions?

Community
  • 1
  • 1
jtheman
  • 7,421
  • 3
  • 28
  • 39
  • From what I remember, `jQuery.validate` does not support validation of multiple fields with the same name like that, not even if you'd remove the numbers between brackets (which you can do when sending it to most back-end languages). Try using `$('input').rules("add", { required:true, extension: "pdf|docx?" })` – Fabrício Matté Mar 12 '13 at 13:56
  • Thanks! The input fields are added dynamically so I can't use your suggestion as the inputs are not in DOM. Also I'm using the array key to keep track of many things in the form so I can't just set `name="field[]"` which would work with the validation... – jtheman Mar 12 '13 at 14:01
  • Use `.rules("add", {})` for each dynamically generated field. There is no other option that doesn't involve uglier hacks. – Fabrício Matté Mar 12 '13 at 14:02
  • Thanks. It worked. Add as your answer and I will accept. My solution was to add the rule for each dynamically added inputfield: `$('input[name="field['+key+']"]').rules("add", { required:true, extension: "pdf|doc|docx" });` (`key` was my variable with the number...) – jtheman Mar 12 '13 at 14:06

3 Answers3

2

You can apply .rules("add", rules) to each generated element:

$(element).rules("add", { required:true, extension: "pdf|docx?" });

jQuery.validate does provide a way to validate elements with the same name (foo[] nor foo[N]) through the rules set on a form (at least up to v1.11).

There are some other ways for adding dynamic rules, for example, to add a required check without calling .rules('add') you can simply use class="required" in the element and the validation plugin should pick it up dynamically.

However, there is no built-in equivalent to the extension option so you'd have to add a class to all inputs and create your own class rules with addClassRules. This ends up mixing a bit of behavior with HTML and possibly CSS though.


Note for future readers: both .rules('add') and addClassRules do not work for repeated names (e.g. foo[]) but these do work if the name is not exactly the same (e.g. foo[index]) which is OP's case.

I believe inputs with the exact same name is off-topic for this question, but for these you either have to add your own validation method with addMethod, or add your own validation inside the form's submit handler or try this related answer.

Community
  • 1
  • 1
Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • 1
    @jtheman In regex, `?` makes the character preceding it optional. – Fabrício Matté Mar 12 '13 at 14:10
  • Yes I know about setting the `class="required"`, I was also considering a solution to use `addMethod()` to add a custom method to validate the extension. Probably possible too? – jtheman Mar 12 '13 at 14:16
  • 1
    @jtheman Yes it is possible. `=]` `addMethod` is very handy if you need some custom validation. – Fabrício Matté Mar 12 '13 at 14:17
  • I was reviewing this old answer that I was referencing and using in my question: http://stackoverflow.com/questions/9996589/jquery-validate-add-rules-for-an-array-input?rq=1 It actually is wrong, the solution is non working... – jtheman Mar 12 '13 at 14:23
  • 1
    @jtheman Yes, I never got that syntax to work. It gives a false impression that it is working because the validation picks in the first element, but not the rest if you have more than one with the same name. – Fabrício Matté Mar 12 '13 at 14:26
  • Regarding your final "note". That's not entirely correct... you simply use an `.each()` and a "wildcard", "starts with", or class selector. See my answer. – Sparky Mar 12 '13 at 15:25
  • @Sparky My final note is for *exact* same name, not with `index`. I've edited that note to note that it is off-topic to this question. – Fabrício Matté Mar 12 '13 at 15:28
  • Yes, and as far as the OP's question, it can be solved with a `rules('add')` inside of a jQuery `.each()`. – Sparky Mar 12 '13 at 15:33
  • @Sparky Commented about that on your answer. `=]` If the fields weren't dynamically added, then a `.each` would be the best way to go, of course. – Fabrício Matté Mar 12 '13 at 15:35
  • Yes, OP should edit question to include the code that adds fields, instead of making comments. – Sparky Mar 12 '13 at 15:39
  • @Sparky Thanks for your suggestion. My original question was how to apply a rule on an input array, and from Fabrícios answer and help showed that that wasn't possible. When first posted I could not guess it would be relevant that input items was dynamically genererated. So I think updating the question in the sense you suggest would make it quite another question and that is not a good practise here at SO I think. – jtheman Mar 12 '13 at 17:55
  • 2
    @jtheman, Yes, in general "chameleon-questions" are a bad practice. However, in this case, simply editing your modest clarifications into your question would have been preferred over placing them in comments. Otherwise, one answer may be more relevant to solving your problem than a different answer that's more relevant to your OP. – Sparky Mar 12 '13 at 18:05
  • I agree with @Sparky. A question that has an accepted answer isn't bumped on the Newest list if you edit it as far as I remember so there's no problem editing these. – Fabrício Matté Mar 12 '13 at 18:07
1

I think the answer given is right, but it is also worth considering creating a class rule combining your two rules, then give your inputs this class. That way you don't have to call addMethod each time you dynamically add a new element to the DOM.

$.validator.addClassRules("myinput", { required:true, extension: "pdf|docx?" });

html

<input name="field[19]" type="file" class="myinput"> 
<input name="field[22]" type="file" class="myinput"> 
<input name="field[25]" type="file" class="myinput">
politus
  • 5,996
  • 1
  • 33
  • 42
  • Thanks, this was what I initially was looking for! However now I stick to the previous solution (noone is paying me for changing it again...) :D +1 to you! – jtheman Mar 12 '13 at 15:04
1

EDIT: My answer was posted on the original version of the question, where without reading comments, it was unknown that these fields are dynamically created. Otherwise, it may be preferred to simply add the rules as each field is created:

var myRule = { // save some code... put the common rule into a variable
    required:true,
    extension: "pdf|docx?"
};

$('a#addfield').click(function(e) {
    e.preventDefault();
    var data = '<p><input type="file" name="field['+key+']"></p>';
    $('div#inputcontainer').append(data);
    $('[name="field['+key+']"]').rules("add", myRule); // add the rule to the new field
});

(Nested brackets handled as per this answer.)

original answer follows:


The accepted answer gets you halfway there.

Also, my answer does not require an additional class or any other changes to your existing HTML structure. This is all jQuery...

The first half is to use the built-in rules('add') method.

$(element).rules("add", {
    required:true,
    extension: "pdf|docx?"
});

The second half is to get that method applied to all elements with named "field[19]", "field[20]", "field[21]", etc.

You simply use a jQuery .each() with a jQuery "starts with" selector.

$('[name^="field"]').each(function() {
    $(this).rules("add", {
        required:true,
        extension: "pdf|docx?"
    });
});

DEMO: http://jsfiddle.net/cWABL/

Community
  • 1
  • 1
Sparky
  • 98,165
  • 25
  • 199
  • 285
  • Remember that fields are added dynamically. With this, if you plan to use this code whenever an input is added, you'd query the DOM multiple times unnecessarily re-adding rules that already exist for those elements. – Fabrício Matté Mar 12 '13 at 15:30
  • @FabrícioMatté, you are correct. However, my answer only applies to the OP _as it's presently written_. If the OP could show the code that actually adds the field, perhaps a better answer can be provided. – Sparky Mar 12 '13 at 15:38
  • Yes, your answer can help future visitors that have an issue to similar to the questioner's code. As for dynamically generated inputs that OP has, it is just a simple matter of replacing the loop with applying the `.rules('add')` to each generated input. – Fabrício Matté Mar 12 '13 at 15:41
  • @FabrícioMatté, it also depends on _how_ the fields are dynamically created... one at a time (as needed at any time), or all at once. – Sparky Mar 12 '13 at 15:45
  • Yeah, in case all are added at a time, you also need to iterate with `.each` after they're generated because, for some reason, `$(els).rules()` only applies to the first element inside of the object... Sometimes all these "bugs", peculiarities and lack of support for some basic features (same name field validation) makes me want to write my own validation plugin. – Fabrício Matté Mar 12 '13 at 16:03
  • @FabrícioMatté, I have no problem with jQuery Validate... I think it's an excellent plugin. However, the incomplete documentation needs to be re-written from scratch. – Sparky Mar 12 '13 at 16:06
  • I can usually put up with these peculiarities as `.rules` not iterating over the object and not returning the jQuery object. Nevertheless if you ever find a good way to do deal with fields with the same name (`arr[]`) @ me. `=]` So far, the best way that I've found was in my answer's linked answer which isn't a clean solution, so I usually end up adding my own validation to the form's submit. I guess there's no point in making a question for that as it'd be a duplicated of the linked question. – Fabrício Matté Mar 12 '13 at 16:09
  • This is a good answer indeed. Adding rules - in my case - could also be done on the dynamically generated input fields when added instead of iterating on `each()` element. +1 to you and thanks. – jtheman Mar 12 '13 at 18:02
  • 1
    @jtheman, I'm glad you got it figured out. I posted my answer, after you accepted the other, mostly as a service to the casual reader who may simply take the OP as written, without reading the comments. Thank-you! – Sparky Mar 12 '13 at 18:08
  • Well written Q and A is the fine thing about SO. Lets keep it as good as possible. Thanks. – jtheman Mar 12 '13 at 18:16
  • 1
    @jtheman, and in that same spirit, I've edited my answer to be more relevant to your specific situation. – Sparky Mar 12 '13 at 18:23