Tuesday, May 1, 2012

jquery validation against dynamic fields


I'm using jQuery's validation plugin and looking to validate many dynamically added text fields such that their summation is checked against a separate total field.



I've written my own validation methods in the past, but only simple ones that take on the basic regex structure that is easy to reproduce from the additional-methods.js file.



Specifically, the jQuery website gives a simple example of using the addMethod() function to do something quite similar:




jQuery.validator.addMethod("math", function(value, element, params) {
return this.optional(element) || value == params[0] + params[1];
}, jQuery.format("Please enter the correct value for {0} + {1}"));



The implementation of the params parameter is more-or-less poorly documented. I was able to find how to pass content into params in a seperate stackoverflow thread . However, the array passed into params in that example is static. The array I need to pass to params grows and shrinks based on dynamically added rows added at 'runtime'...



I've uploaded a completely stripped down version onto jsfiddle for your viewing. Note that the code has some comments embedded where I have questions, and also, I removed the Remove functionality, as it only adds clutter and doesn't help illustrate the point.



So how can I use the jQuery validation library to ensure that dynamically added fields add to a specific total? Thank you in advance!


Source: Tips4all

4 comments:

  1. Here is my version of your validator.

    http://jsfiddle.net/linkabi9/shBxv/

    You'll notice that instead of static numbers for parameters, I pass a selector. The one element in the array is a selector for the deposit fields. I gave every existing and new deposit input a class, "setamount1", you can use any class you want. The field you set this validator to will be the "Total Amount" field.

    I also added a live "change" event to the deposit fields. This will run the validation on every change. I have to warn you, this runs validation on the whole form not just the deposit & total fields.

    Now you can reuse this validator type multiple times in the same form/page!

    I went ahead and put the validator code below. Plus, an example of the validator initialization.

    jQuery.validator.addMethod("depositsSum", function(value, element, params)
    {
    var amnts = 0;
    $(params[0]).each(function() {
    amnts += parseFloat($(this).val());
    });

    return this.optional(element) || amnts == parseFloat(value);
    }, jQuery.format("Individual deposits must add up to the total!"));

    $("#depositForm").validate({
    rules: {
    fullAmount: {
    depositsSum: [".amountset1"]
    }
    }
    });

    ReplyDelete
  2. Try to use like this in ur input html code...

    <input id="check" name="check" type="text" class="required math">


    Once u dynamically create input tag as above then it would be validated as per ur add method.. Try it..

    ReplyDelete
  3. So, first you need a way to calculate the total of all dynamic fields. One way to do so is by marking all such fields with a class. Let's say we call them "amount". You can then calculate the sum of them with this

    var total = 0;
    $('#depositForm input.amount').each(function() {
    total += Number($(this).val());
    });


    Now, you'll need to pass this total value to the validation method. Since javascript has closures you can do the following

    $("#depositForm").validate({
    rules: {
    fullAmount: {
    depositsSum: function() {
    var total = 0;
    $('input.amount').each(function() {
    total += Number($(this).val());
    });
    return total;
    }
    }
    }
    });


    This function will be executed every time and its result will be your param value. So the validation function will ultimately be

    function(value, element, total) {
    return this.optional(element) || value == total;
    }


    For the second part of the question, running the validation for the dynamic fields, there are two approaches. Either have a validation marking class or use the rule("add", ) and rule("remove", ) methods everything to insert/remove a dynamic field.
    Here's an example of the class approach:
    Let all validated fields (dynamic and total) have class "checkSum". Then:

    $.validator.addClassRules("checkSum", {
    depositsSum: function() {
    var total = 0;
    $('input.amount').each(function() {
    total += Number($(this).val());
    });
    return total;
    }
    });
    $("#depositForm").validate();


    Here's a JSFiddle of it all.

    Of course you'll notice that this doesn't work as you might thought it would. For your application the kind of validation you're looking for is full form validation triggered by field change, not field validation. Play around a bit with it and see what I'm talking about

    ReplyDelete
  4. This includes adding and removing rows with a live updating price. [ download ]

    <html>

    <head>

    <script src="http://www.google.com/jsapi" type="text/javascript"></script>
    <script type="text/javascript">google.load("jquery", "1");</script>
    <script type="text/javascript">

    $(document).ready(
    function()
    {
    $('.add-row').click(
    function()
    {
    addRow();
    return false;
    }
    );

    addRow();
    }
    );


    function addRow()
    {
    var newRow = '<li class="deposit"><input class="price"> <a href="#" class="remove">Remove</a></li>';

    $('.deposits').append(newRow);
    $('.deposit:last .price').select();

    setListeners();
    }

    function removeRow(val)
    {
    $(val).parents('.deposit').remove();

    sumDeposits();
    }

    function setListeners()
    {
    $('.price').each(
    function()
    {
    $(this).keyup(
    function()
    {
    sumDeposits();
    }
    );
    }
    );

    $('.remove').each(
    function()
    {
    $(this).click(
    function()
    {
    removeRow(this);
    }
    );
    }
    );
    }


    function sumDeposits()
    {
    var total = 0;

    $('.price').each(
    function()
    {
    total += Number( $(this).val() );
    }
    );

    $('.total').html(total);
    }

    </script>

    </head>

    <body>

    <h3>Total is <span class="total">N/A</span></h3>

    <p><a href="#" class="add-row">Add</a></p>

    <ul class="deposits"></ul>

    </body>

    </html>

    ReplyDelete