0

I'm trying to validate a complex form and by complex I mean that form is just one but it has been split in four sections and I made a simple wizard to show them. I'm using jQuery Validation but it's not working as I want and also have some doubts about it. Based on this example (second form) I made my code as follow:

$("#product_create").validate({
    rules: {
        product_name: {
            required: true,
            minlength: 10,
            maxlength: 50
        },
        product_price: {
            required: true,
            number: true,
            minlength: 2
        },
        product_quantity: {
            required: true,
            digits: true,
            minlength: 1
        }
    },
    messages: {
        product_name: {
            required: "El nombre del producto no se puede dejar vacío",
            minlength: "El nombre del producto no puede tener menos de 10 carácteres",
            maxlength: "El nombre del producto no puede tener más de 50 carácteres"
        },
        product_price: {
            required: "Debes introducir un precio",
            number: "El precio debe ser un número decimal o no"
        },
        product_quantity: {
            required: "Debes introducir una cantidad",
            number: "La cantidad debe ser un número"
        }
    }
});

If I understand good then on keyup event fields should validate and they are not since errors doesn't come up. So first problem regarding this is: why it doesn't validate? What's wrong in my solution? Second one is how I validate product_price and product_quantity only if they are visible?

Now regarding this same topic I have another doubt, I create several fields on the fly and yes I know theirs ID each time, in this case how I apply rules to those fields?

UPDATE

I figure out where the problem with keyup was, validation is made by input name and not input id's as I tough, so this part is done.

The second problem still pending. For example I can generate three fields with name variation[pprice][] and the fly but can be five or more or whatever, how I add those fields to rules and validation part? Can I just add the rule for variation[pprice][] and it will validates no matter how many elements with the same name are in the form?

Also is pending the part of validate fields just if they are visible

UPDATE 2

Since variation[pprice][] is a array of items, can I use $.each to move for them and assign rules?

UPDATE 3

Following recommendations by @Sparky I change my code to this:

$('#variations_holder input.pprice').each(function() {
    $(this).rules('add', {
        required: true,
        number: true,
        messages: {
            required: "Debes introducir un precio de la variación",
            number: "El precio de la variación debe ser un valor numérico o decimal"
        }
    });
});

But in Firebug I get this error:

TypeError: e.validator.methods[o] is undefined

Which prevent code execution for the script, what I miss in this case?

UPDATE 4

Supposing that I can't use several forms so I only have one form with many sections (using section tag) and I handle to move between each. I'm trying to call validate() in same form but two times and validation at step5 didn't work since fields pass. This is the code I'm using for that:

function validateWizard(step) { var is_valid = true;

switch (step) {
    case 1:
        if ($("#selected_category").val() === '' || $("#selected_category").val().length === 0) {
            alert("Debes seleccionar una categoría antes de continuar");
            is_valid = false;
        }
        break;
    case 2:
        $("#product_create").validate({
            rules: {
                "product[name]": {
                    required: true,
                    minlength: 10,
                    maxlength: 50
                },
                "product[price]": {
                    required: true,
                    number: true,
                    minlength: 2
                },
                "product[quantity]": {
                    required: true,
                    digits: true,
                    minlength: 1
                },
                "product[description]": {
                    required: true
                }
            },
            messages: {
                "product[name]": {
                    required: "El nombre del producto no se puede dejar vacío",
                    minlength: "El nombre del producto no puede tener menos de 10 carácteres",
                    maxlength: "El nombre del producto no puede tener más de 50 carácteres"
                },
                "product[price]": {
                    required: "Debes introducir un precio",
                    number: "El precio debe ser un valor numérico o decimal"
                },
                "product[quantity]": {
                    required: "Debes introducir una cantidad",
                    number: "La cantidad debe ser un número"
                },
                "product[description]": {
                    required: "Debes introducir una descripción del producto"
                }
            }
        });

        is_valid = $("#product_create").valid();

        if (is_valid) {
            $('#variations_holder input.pprice').each(function() {
                pprice = $.trim(this.value);
                if (!pprice.length) {
                    $(this).focus();
                    $(this).addClass('error');
                    is_valid = false;
                } else if (!/^[1-9]\d*(\.\d+)?$/.test(pprice)) {
                    $(this).addClass('error');
                    is_valid = false;
                }
            });

            // Validate quantity in variation
            $('#variations_holder input.pqty').each(function() {
                pqty = $.trim(this.value);
                if (!pqty.length) {
                    $(this).focus();
                    $(this).addClass('error');
                    is_valid = false;
                } else if (!/^[1-9]\d*$/.test(pqty)) {
                    $(this).addClass('error');
                    is_valid = false;
                }
            });
        }
        break;
    case 3:
        break;
    case 5:
        $("#product_create").validate({
            rules: {
                "stock[sku]": {
                    required: true,
                    minlength: 10,
                    maxlength: 20
                },
                "stock[width]": {
                    required: true,
                    number: true,
                    minlength: 1
                },
                "stock[height]": {
                    required: true,
                    number: true,
                    minlength: 1
                },
                "stock[length]": {
                    required: true
                },
                "stock[weight]": {
                    required: true,
                    number: true,
                    minlength: 1
                },
                "stock[description]": {
                    required: true
                },
                "warranty[description]": {
                    required: true
                },
                "warranty[valid_time]": {
                    required: true,
                    digits: true
                }
            },
            messages: {
                "stock[sku]": {
                    required: "El SKU no se puede dejar vacío",
                    minlength: "El SKU no puede tener menos de 10 carácteres",
                    maxlength: "El SKU no puede tener más de 50 carácteres"
                },
                "stock[width]": {
                    required: "Debes introducir un ancho",
                    number: "El ancho debe ser un número"
                },
                "stock[height]": {
                    required: "Debes introducir una altura",
                    number: "La altura debe ser un número"
                },
                "stock[length]": {
                    required: "Debes introducir una longitud",
                    number: "La longitud debe ser un número"
                },
                "stock[weight]": {
                    required: "Debes introducir un peso",
                    number: "El peso debe ser un número"
                },
                "stock[description]": {
                    required: "Debes introducir una descripción del stock del producto"
                },
                "warranty[description]": {
                    required: "Debes introducir una descripción de la garantía para este producto"
                },
                "warranty[valid_time]": {
                    required: "Debes introducir un período de validez",
                    digits: "El período de validez no es válido"
                },
            }
        });

        is_valid = $("#product_create").valid();
        break;
}

return is_valid;

}

my question is why if form is not valid at step5 it pass? Should't fail?

Reynier
  • 2,420
  • 11
  • 51
  • 91
  • 1
    please, post your html code, at least those fields that you validate in the js code that you posted. – Claudio Santos Oct 08 '13 at 16:19
  • You cannot have multiple elements with same name. jQuery Validate requires that the name be unique. – Sparky Oct 08 '13 at 16:44
  • Can I assume that jquery validate through name tag, then to avoid that jquery validate some fields, could you remove the name of a html element and try to validate to see if the jquery validate them? – Claudio Santos Oct 08 '13 at 16:48
  • @Sparky any way to handle this? maybe using ID's instead of names? – Reynier Oct 08 '13 at 17:29
  • @ClaudioSantos the code isn't the problem here, the problem is validity of visible fields and fields created on the fly with same name – Reynier Oct 08 '13 at 17:30
  • I supossed that jquery doesn't provide a half validate, so the way to solve this is to remove the link between validate config and validate fields. – Claudio Santos Oct 08 '13 at 17:43
  • @ClaudioSantos ups and how? This is advanced jQuery for me tough – Reynier Oct 08 '13 at 17:51
  • when you hide some fields, also remove the tag name and try. `$('#element').attr('name',null)` – Claudio Santos Oct 08 '13 at 17:59
  • @ClaudioSantos I think you didn't understand me, what I said is I have two input field with validator rules by default but those fields can be hidden by checking a `checkbox` in those cases those fields should't validate – Reynier Oct 08 '13 at 18:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38815/discussion-between-claudio-santos-and-reynier) – Claudio Santos Oct 08 '13 at 18:08
  • A group of radio or checkbox elements with the same name is not an issue since, when they're grouped, they're supposed to have the same name. The jQuery Validate plugin needs unique names on data input elements because that's how the plugin keeps track of them internally. There is no way around this requirement. – Sparky Oct 08 '13 at 19:13

2 Answers2

1

Quoet OP:

"Since variation[pprice][] is a array of items, can I use $.each to move for them and assign rules?"

You must use .each() when the jQuery selector targets more than one input element. However, this does not get around the fact that the jQuery Validate plugin requires that each input element contain a unique name attribute. This is how the plugin keeps track of elements. (A group of radio or checkbox elements with the same name is not an issue since, when they're grouped, they're supposed to have the same name... the group acts as a single data input.)

This will not work because there are multiple input elements with the same name...

$('input[name="something"]').each(function() {
    $(this).rules('add', function() {
        required: true,
        // another rule, etc,
    });
});

This will work as long as each input element contains a unique name...

$('input.class').each(function() {
    $(this).rules('add', function() {
        required: true,
        // another rule, etc,
    });
});

See this answer for the various ways rules can be defined and applied.


There are various approaches to stepped forms.

When I create multi-step forms, I use a unique set of <form> tags for each section. Then I use the .valid() method to test the section before moving to the next. (Don't forget to first initialize the plugin; call .validate(), on all forms on DOM ready.)

Then on the last section, I use .serialize() on each form and concatenate them into a data query string to be submitted.

Something like this...

$(document).ready(function() {

    $('#form1').validate({ // initialize form 1
        // rules
    });

    $('#gotoStep2').on('click', function() { // go to step 2
        if ($('#form1').valid()) {
            // code to reveal step 2 and hide step 1
        }
    });

    $('#form2').validate({ // initialize form 2
        // rules
    });

    $('#gotoStep3').on('click', function() { // go to step 3
        if ($('#form2').valid()) {
            // code to reveal step 3 and hide step 2
        }
    });

    $('#form3').validate({ initialize form 3
        // rules,
        submitHandler: function (form) {
           // serialize and join data for all forms
           // ajax submit
           return false;
        }
    });

    // there is no third click handler since the plugin takes care of this 
    // with the built-in submitHandler callback function on the last form.

});

Important to remember that my click handlers above are not using type="submit" buttons. These are regular buttons, either outside of the form tags or type="button".

Only the button on the very last form is a regular type="submit" button. That is because I am leveraging the plugin's built-in submitHandler callback function on only the very last form.

"Proof of Concept" DEMO: http://jsfiddle.net/N9UpD/

Also, see for reference:

https://stackoverflow.com/a/17975061/594235

Community
  • 1
  • 1
Sparky
  • 98,165
  • 25
  • 199
  • 285
  • Excellent answer I change votes to you. Now I have a doubt, since rules are added based on name how I assign them in your approach? Can you edit your answer and supply at least one fake definition? – Reynier Oct 09 '13 at 18:20
  • @Reynier, rules are not necessarily "added by name". [There are many different ways to add rules](http://stackoverflow.com/a/9461732/594235). **However**, each element **must** contain a _unique_ `name`, no matter how the rules are created and applied. – Sparky Oct 09 '13 at 18:48
  • @Reynier, see this answer for the various ways you can define and apply rules: http://stackoverflow.com/a/9461732/594235 – Sparky Oct 09 '13 at 18:49
  • Almost done and working, please take a look at my 3th edition since I'm getting some issues and I'm not sure in how to fix them, I think is something with declaration but can't get it to work – Reynier Oct 09 '13 at 19:01
  • @Reynier, please proof your code. It's `$(this).rules('add', {...`. Notice that it's not a function as the second argument. Wrong: `$(this).rules('add', function () {...`. See: http://jsfiddle.net/ZfRxv/ – Sparky Oct 09 '13 at 19:14
  • Thanks this is fixed but now I get this error `TypeError: e.validator.methods[o] is undefined ... n=this.errorList[e];this.settings.highlight&&this.settings.highlight.call(this,..` this happens when I attempt to validate on the fly fields meaning `#variations_holder input.pprice` validation don't pass and for that reason I can continue the process – Reynier Oct 09 '13 at 19:27
  • @Reynier, I don't understand what you're asking. Put your code into a jsFiddle so I can see it fail. – Sparky Oct 09 '13 at 20:09
  • Dismiss the previous comment and take a look at the 3th edition in main post, there is the problem – Reynier Oct 09 '13 at 20:12
  • @Reynier, at some point you're going to have to stop appending this question and just post a new one with your latest issue. However, the code in your third revision is not giving me any error: http://jsfiddle.net/ZfRxv – Sparky Oct 09 '13 at 20:15
  • Here is [the post](http://stackoverflow.com/questions/19282526/validation-of-fields-with-same-name-and-class-get-typeerror-e-validator-method) please take a look and see what test I've done – Reynier Oct 09 '13 at 20:55
  • @Reynier, you've again tried to use the same `name` more than once. This is the cause of your problem. There is no workaround. – Sparky Oct 09 '13 at 21:59
  • can you take a look at "UPDATE 4", what did you suggest on that case? – Reynier Oct 11 '13 at 20:00
  • @Reynier, I suggest that you please stop adding totally new questions to this old question. [Just post a new question](http://stackoverflow.com/questions/ask). Thanks. – Sparky Oct 11 '13 at 21:02
0

Supposed that you set a config rules each time you load a step, then you can keep one config rules for each step.

To remove the validation of the hidden fields, you could create a JavaScript function called each time you changed the visibility's fields, at this function you can set again the config rules or you could remove the link between the config rules and the field elements, only for the hidden fields. I understod that this link is the tag name, to set the tag name you can use this code$('#element').attr('name',null).

Claudio Santos
  • 1,307
  • 13
  • 22