SitePoint Sponsor

User Tag List

Page 3 of 8 FirstFirst 1234567 ... LastLast
Results 51 to 75 of 184
  1. #51
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Thank you where you are from actually.
    I'm from Christchurch, which had that city-destroying earthquake, before Japan took our thunder when their tsunami wiped out have the country.

    Quote Originally Posted by newtomysql View Post
    Anyway I have implemented the new codes it works but can just add one row and nothing beyond that ready.
    There should be a clone added to the code.

    Code javascript:
    var prot = master.data('prototype').clone();

    Quote Originally Posted by newtomysql View Post
    Then I notice also it only normally validate the first row and not the second one.
    That's a problem due to the form name being identical. We should be able to deal with that by placing an array index in the brackets.

    Try this just before the prot is added:

    Code javascript:
    prot.find('input[name="name[]"]').attr('name', 'name[' + id + ']');

    It should result in the name field for the id 2 row looking like this:
    Code html4strict:
    <input type="text" name="name[2]" value="" class="required">
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  2. #52
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    So how is your state coping up with things I guess better now. The only thing we can do is pray for peace. Anyway why without the clone is does not add more rows? I dont quite understand this part of the codes prot.find('input[name="name[]"]').attr('name', 'name[' + id + ']'); so how about this what difference is the array here<td><input type="text" name="name[]" value="" class="required" /></td>? Is the array needed in the former ? How to see result as you said e.g <input type="text" name="name[2]" value="" class="required">?

  3. #53
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    So how is your state coping up with things I guess better now.
    It's been over a month and the police are still retrieving cars that were abandoned from the central city. The CBD is still cordoned off, and the police have retrieved around half of the cars from there. It's going to be a very long process of recovery, taking years.

    Quote Originally Posted by newtomysql View Post
    The only thing we can do is pray for peace.
    Prayer may help how people feel about things, but they are not of much use when actual assistance is required.

    Quote Originally Posted by newtomysql View Post
    Anyway why without the clone is does not add more rows?
    Because unless you create a completely separate version of prot, it will be a direct reference to the one that has already been added to the DOM. That means, all future references to the stored prototype will also be references to the added row as well. When you attempt to append content that is already in the DOM, it's removed from where is was and is added to where you want to put it. In the case of our rows, that just means the last row is removed then put back in again.

    That is why a separate clones are required when you want to add multiple copies of the same object to the DOM.

    Quote Originally Posted by newtomysql View Post
    I dont quite understand this part of the codes prot.find('input[name="name[]"]').attr('name', 'name[' + id + ']');
    If the id were 2, instead of "name[]" it sets it to "name[2]" instead.

    The purpose of "name[]" is so that PHP treats it as if it were an array. The problem with "name[]" is that the validator cannot process other identically named fields when they're dynamically added afterwards. Using "name[2]" continues to meet the needs of PHP treating it as an array, while resolving the validation issue.

    Quote Originally Posted by newtomysql View Post
    so how about this what difference is the array here<td><input type="text" name="name[]" value="" class="required" /></td>?
    The difference there is that none of the added rows will be validated, because they have the same identical name as other fields in the same form.

    Quote Originally Posted by newtomysql View Post
    Is the array needed in the former ?
    The array notation is only needed when you are using PHP to retrieve the values from the form as if they were an array.

    Quote Originally Posted by newtomysql View Post
    How to see result as you said e.g <input type="text" name="name[2]" value="" class="required">?
    In Google Chrome I right-click and choose Inspect Element.
    If using Internet Explorer, I open up the Developer Tools
    I don't use Firefox much now, but that has an extension called Firebug that allow you to do such things too.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  4. #54
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Sorry to you and your fellow people of your nation. I know it will take some time to build the state. So I guess you are in safe location. Hopefully you and your family is in safe condition. Thank you for all the clarifications which help me understand better about jquery. I got one question which is more of a logical settings. I would like to control such a way where if there is only one row I wont validate even though all is empty. The reason is if just one row might be the person does not want to enter any data or there is no data entry going to happen. IS this possible?

  5. #55
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    I would like to control such a way where if there is only one row I wont validate even though all is empty.
    You would need to create a custom validation rule to replace required, which could instead be called requiredWithMultipleRows

    Code html4strict:
    <input type="text" name="name[]" value="" class="requiredWithMultipleRows" />

    And we add a new method before we initialize the validator. I'll start with returning false which will force the field to always fail validation.

    Code:
    $.validator.addMethod("requiredWithMultipleRows", function(value, element) {
        return false;
    }, "This new field is required.");
    $("#form1").validate();
    Because we do want the validation method to behave the same as the normal return when our condition of multiple rows is met, let's first reproduce what's needed to validate as required.

    We can do that by executing the required method in the context of the existing environment, by using the apply method so that we the context of the current function can be passed along:

    Code:
    $.validator.addMethod("requiredWithMultipleRows", function(value, element) {
        $.validator.methods.required.apply(this, arguments);
    }, "This new field is required.");
    How did I find out about $.validator.methods? I set a breakpoint in the function, and investigated some obvious objects, such as $.validator and the this keyword.

    We only want to use the standard required method if there are multiple rows. We can get the number of rows by searching the current form, (provided as this.currentForm) for the field named id[] and counting the number of them.

    How did I find out about this.currentForm? I set a breakpoint in the function, and investigated some obvious objects, such as $.validator and the this keyword.

    Code:
    $.validator.addMethod("requiredWithMultipleRows", function(value, element) {
        $numOfRows = $('input:[name="id[]"]', $.currentForm).length;
        if ($numOfRows > 1) {
            return $.validator.methods.required.apply(this, arguments);
        }
        return true;
    }, "This field is required.");
    That should now give us a method that does what we need, but let's make it more obvious why we're doing this.
    The id statement is refactored to make it clear that validation will succeed only when there is one row.

    Code javascript:
    $.validator.addMethod("requiredWithMultipleRows", function(value, element) {
        $numOfRows = $('input:[name="id[]"]', $.currentForm).length;
        if ($numOfRows === 1) {
            return true;
        } else {
            return $.validator.methods.required.apply(this, arguments);
        }
    }, "This field is required.");
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  6. #56
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    You are real super expert yes it works as how it suppose to be but give me some time to digest the new codes as you know I am new to this jquery will be back with some doubts. Ok one more thing just say at this level of the code if ($numOfRows === 1) { I would like to check if any of the column is written and the other is empty then can I enforce the other validation to warn on the empty column.

  7. #57
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Dear Paul,
    You are real super expert yes it works as how it suppose to be but give me some time to digest the new codes as you know I am new to this jquery will be back with some doubts. Ok one more thing just say at this level of the code if ($numOfRows === 1) { I would like to check if any of the column is written and the other is empty then can I enforce the other validation to warn on the empty column.
    Shall we apply that to all the rows, where the name is required only if the other fields (excluding the id one of course) have any content?
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  8. #58
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Ok we can go with your idea so how to implement that when just one row is available. Thank you.

  9. #59
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Dear Paul,
    Ok we can go with your idea so how to implement that when just one row is available. Thank you.
    I think that you're going to list all of the conditions under which fields will be considered required or not, because I'm getting confused about things now.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  10. #60
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Ok sorry lets now clear things. Imagine got just one row only. So incase the user just key in any of the column then I must validate the rest. If the user left all empty then is ok the form can be submitted. I hope I am clearer now? Thank you.

  11. #61
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Dear Paul,
    Ok sorry lets now clear things. Imagine got just one row only. So incase the user just key in any of the column then I must validate the rest. If the user left all empty then is ok the form can be submitted. I hope I am clearer now? Thank you.
    Okay, that's with one row. But we're also adding multiple rows, so do the same rules apply when there's more than one row? If not, what are the rules you require for multiple rows.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  12. #62
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Yes the same rule apply. I was thinking if could settle for one row then can replicate it over the next rows right? So how to go about that? Need additional logics is it?

  13. #63
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Dear Paul,
    Yes the same rule apply. I was thinking if could settle for one row then can replicate it over the next rows right?
    That will help. Can you help us too by occasionally linking to the code that you're currently using. Doing that makes it so much easier for us to help you.

    Quote Originally Posted by newtomysql View Post
    So how to go about that?
    It should be as easy as renaming requiredWithMultipleRows to something that explains the new validation, and updating the addMethod function for the new validation method.

    Something like requiredWithFieldsToRight should do.

    Code html4strict:
    <input type="text" name="name[]" value="" class="requiredWithFieldsToRight" />

    We can replace the other addMethod function with a nice clean one that we will fill out:

    Code javascript:
    $.validator.addMethod("requiredWithFieldsToRight", function(value, element) {
        ...
    }, "This field is required.");

    So what do we do. First we get the elements on the row that come after it.

    Code javascript:
    var $inputs = $(element).closest('td').nextAll().find('input');

    We can then search through those for any inputs that have some content:

    Code javascript:
    var $inputsWithContent = $.grep($inputs, function(field) {
        return field.value > '';
    });

    If that $inputsWithContent is empty, we can return true to say that the field is okay.
    Otherwise, we send the field to the standard "required" method.

    Code javascript:
    if ($inputsWithContent.length === 0) {
        return true;
    } else {
        return $.validator.methods.required.apply(this, arguments);
    }

    Putting that all together gives us:

    Code javascript:
    $.validator.addMethod("requiredWithFieldsToRight", function(value, element) {
        var $inputs = $(element).closest('td').nextAll().find('input');
        var $inputsWithContent = $.grep($inputs, function(field) {
            return field.value > '';
        });
        if ($inputsWithContent.length === 0) {
            return true;
        } else {
            return $.validator.methods.required.apply(this, arguments);
        }
    }, "This field is required.");
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  14. #64
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    So must I make all the class for the field to be requiredWithFieldsToRight for it to function well is it. I would like to learn now this code below what exactly it does please correct me, is it that from this particular column it look for the next column and check all the columns. If any of the column is not empty it will raise the required for this particular field?
    " var $inputs = $(element).closest('td').nextAll().find('input'); var $inputsWithContent = $.grep($inputs, function(field) { return field.value > ''; });

    So for the updates about my code. What ever you asked me to do I have always updated is at here http://183.78.169.54/v3/dynamicrow.php. I have modified your new code with the inclusion of the check where it check only if it row==1 then apply this else apply the normal rules. The problem now is the required=number where when I try to send if it is empty no error. I know what I want is that it cant be empty and at the same it have to be a number. Any idea how to modify it?

  15. #65
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    The problem now is the required=number where when I try to send if it is empty no error.
    15 hours ago you were saying the opposite:

    Quote Originally Posted by newtomysql View Post
    If the user left all empty then is ok the form can be submitted. I hope I am clearer now?
    Things are now very unclear again. Please come to a conclusion on what you want to achieve.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  16. #66
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Ok to make things simple just for single row if any of the column is filled then the rest of the columns must be filled else if all is empty is ok. But for the rest all the columns must field. For the case of single row if I filled the first left column and dont fill the rest of the column is goes through. Then if I filled the first and third column it goes through but the second colum is empty. I hope I am clearer now.

  17. #67
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Let's get rid of the inline validation rule on the class variable, and use a rules object instead.

    Code html4strict:
    <td><input type="text" name="id[]" value="0" /></td> 
    <td><input type="text" name="name[]" /></td> 
    <td><input type="text" name="col4[]" /></td> 
    <td><input type="text" name="col3[]" /></td>

    I've just noticed that the col4[] field is under the table heading of Col 3. So that my brain doesn't explode when writing this code, I'm going to swap col4[] and col3[]

    Code html4strict:
    <td><input type="text" name="id[]" value="0" /></td> 
    <td><input type="text" name="name[]" /></td> 
    <td><input type="text" name="col3[]" /></td> 
    <td><input type="text" name="col4[]" /></td>

    That's better.

    A simple set of rules for this might look like this:

    Code javascript:
    $("#form1").validate({
        rules: {
            'name[]': required,
            'col3[]': number
        }
    });

    However, the requirements are not that simple.

    The name field is required if col3 is filled or if col4 is filled
    The col3 field is required if name is filled or col4 is filled
    The col4 field is required if name is filled or col4 is filled
    And, col3 is only valid if it is a number.

    That makes the rules a bit more cumbersome, but still manageable.

    Code javascript:
    $("#form1").validate({
        rules: {
            'name[]': {
                required: '[name="col3[]"]:filled, [name="col4[]"]:filled'
            },
            'col3[]': {
                required: '[name="name[]"]:filled, [name="col4[]"]:filled',
                number: true
            },
            'col4[]': {
                required: '[name="name[]"]:filled, [name="col3[]"]:filled'
            }
        }
    });

    So how do we validate things when a row has been added, and the top row has been removed? Since the names on each multiple row must be different for validation to occur, after removing the top row, the [] on each name will instead be that which was on the next row, that being [1].

    To solve that, we can pass the name to a function which finds out what is in the brackets, and applies that suffix to the rules it returns. The following regular expression will find square brackets and whatever those brackets are around.

    Code javascript:
    /\[.*\]/

    So all we need now is a function that can build the rules, and return them. It could be called createSingleRowRules(name)

    Code javascript:
    function createSingleRowRules(field) {
        ...
    }

    We'll need an object to store the rules in, to get the suffix (whether it be '[]' or '[2]' or something else) and some appropriate variables in which to keep those variations of the field names:

    Code javascript:
    function createSingleRowRules(field) {
        var rules = {},
            suffix = /\[.*\]/.exec(field),
            name = 'name' + suffix,
            col3 = 'col3' + suffix,
            col4 = 'col4' + suffix;
        ...
        return rules;
    }

    Then we need to add our settings to the rules. There will be around 6 different sets of dependency rules, such as:
    '[name="col3[2]"]:filled, [name="col4[2]"]:filled'

    so it'll be a good idea to create a function that can receive an array of fields like:
    ['col3[2]', 'col4[2]'] or even [col3, col4]
    and return the above dependency rule.

    Code javascript:
    function filledFields(array) {
        // when given ['name', 'age'] this function will return the following string
        // '[name="name"]:filled, [name="age"]:filled'
        var selectors = [];
        $(array).each(function (i, name) {
            selectors.push('[name="' + name + '"]:filled');
        });
        return selectors.join(', ');
    }

    Now we can add our rules to the rules object with greater ease.

    Code javascript:
    function createSingleRowRules(field) {
        ...
        rules[name] = {
            required: filledFields([col3, col4])
        };
        rules[col3] = {
            required: filledFields([name, col4]),
            number: true
        };
        rules[col4] = {
            required: filledFields([name, col3])
        };
        return rules;
    }

    That's almost readable now. Let's try it for the col3 rule declaration:

    Code javascript:
    rules[col3] = {
        required: filledFields([name, col4]),
        number: true
    };

    Ahem! The rules for the col3 field are that the field is required when there are filled fields for name or col4, and it must be a number.

    Anyway, we can now initialize the form validation with:

    Code javascript:
    var rules = createSingleRowRules('name[]');
    $("#form1").validate(rules);

    And as we add/remove rows, we can update the rules and apply them as need be.

    Here's the HTML and JavaScript for this set of changes:

    Code html4strict:
    <td><input type="text" name="id[]" value="0" /></td> 
    <td><input type="text" name="name[]" /></td> 
    <td><input type="text" name="col3[]" /></td> 
    <td><input type="text" name="col4[]" /></td>

    Code javascript:
    function createSingleRowRules(field) {
        function filledFields(array) {
            // when given ['name', 'age'] this function will return the following string
            // '[name="name"]:filled, [name="age"]:filled'
            var selectors = [];
            $(array).each(function (i, name) {
                selectors.push('[name="' + name + '"]:filled');
            });
            return selectors.join(', ');
        }
     
        var rules = {},
            suffix = /\[.*\]/.exec(field),
            name = 'name' + suffix,
            col3 = 'col3' + suffix,
            col4 = 'col4' + suffix;
        rules[name] = {
            required: filledFields([col3, col4])
        };
        rules[col3] = {
            required: filledFields([name, col4]),
            number: true
        };
        rules[col4] = {
            required: filledFields([name, col3])
        };
        return rules;
    }
    var rules = createSingleRowRules('name[]');
    $("#form1").validate(rules);

    That is the validation for one row all sorted out.

    I'll follow up with the changes from here to handle multiple rows, and to cater for when multiple rows are reduced down to one row again.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  18. #68
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Ok I have uploaded my latest codes ready. I have a problem first the number column was not increasing always zero then I change it to prot.find("id[]").attr("value", id); it works now I dont know that is correct to do or not. Next even for the single row the validations is not working. You can have a look at my code at the site. Thank you.

  19. #69
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Fact 1: Whenever we add a row, we need to set up multiple row rules.

    Fact 2: Whenever we remove a row, we need to check how many rows remain in case we need to setup for the single row rules.

    Fact 3: We also need to run those single row rules when the page starts.

    In light of those three facts, it makes sense to create one function for each type of validation, and a third one that will pick and choose between the two.
    They can be called setupSingleRowRules, setupMultipleRowRules and setupFormValidation so that we can easily run them whenever we need to.

    Let's put those three functions at the start of the jQuery wrapper. The setupSingleRowRules can contain the existing validation code from before.

    We just need to replace references to the master variable so that they use the form instead, and while we're at it we can simplify things too by extracting functions to the top. We'll also help to simplify things by passing a reference to the form in to the function.

    Code javascript:
    $(document).ready(function() {
        function setupSingleRowValidation(form) {
            function filledFields(array) {
                // when given ['name', 'age'] this function will return the following string
                // '[name="name"]:filled, [name="age"]:filled'
                var selectors = [];
                $(array).each(function (i, name) {
                    selectors.push('[name="' + name + '"]:filled');
                });
                return selectors.join(', ');
            }
            function createSingleRowRule(field) {
                var suffix = /\[.*\]/.exec(field),
                    name = 'name' + suffix,
                    col3 = 'col3' + suffix,
                    col4 = 'col4' + suffix;
                return {
                    required: filledFields([name, col3, col4]),
                    number: (field === col3)
                };
            }
     
            ...
       }
     
        ...
    });

    The rest of setupSingleRowValidation needs to now take in to account that multiple row rules may still be on the fields, so we should remove any existing rules before setting up the new rules.

    Code javascript:
    $(document).ready(function() {
        function setupSingleRowValidation(form) {
            ...
     
            // clean up pre-existing rules before adding new ones
            $('tr td:not(:first) input', form).each(function () {
                if ($(this.form).validate().currentElements.has(this).length) {
                    $(this).rules('remove');
                }
     
                var rule = createSingleRowRule(this.name);
                $(this).rules('add', rule);
            });
        }
     
        ...
    });

    When setting up the multiple row validation, we need to remove the old rules in case they were single row rules, and setup the rules. We need all the fields (except the first) to be required, and the ones in the col3 column to be a number.

    Code javascript:
    function setupMultipleRowValidation() {
        var form = $("#form1");
     
        // clean up fields so that they contain the multiple row validation rules
        $(form).validate().currentElements.each(function () {
            $(this).rules('remove');
        });
     
        $('td:not(:first) input', form).each(function () {
            $(this).rules('add', {required: true});
        });
        $('[name^="col3"]', form).each(function () {
            $(this).rules('add', {number: true});
        });
    };

    The setupFormValidation function will only contain a simple if statement. The resetForm part is to remove any error messages from the multiple forms, because they're no long applicable as a single row.

    Code javascript:
    function setupFormValidation(form) {
        if ($('tbody tr', form).length > 1) {
            setupMultipleRowValidation(form);
        } else {
            $(form).validate().resetForm();
            setupSingleRowValidation(form);
        }
    }

    Now we only need two lines to setup the single row validation in the middle of the jQuery wrapper:

    Code javascript:
    $(document).ready(function() {
        ...
                var form = $("#form1");
                setupFormValidation(form);
     
                var prot = $('tr.prototype').clone().removeClass('prototype');
                $(form).data('prototype', prot);
     
                var id = 0;
    });

    and only one line to set things up at the end of the add function. We should though ensure that scoping issues don't affect the id by attaching it as data to the form, along with making surethat all the fields update their field names so that they can be involved when validating multiple form rows.

    Code javascript:
    // Add button functionality
    $("table.dynatable button.add").click(function() {
        var form = this.form;
        id++;
     
        // Get a new row based on the prototype row
        //var prot = master.find(".prototype").clone();
        var prot = $(form).data('prototype').clone();
        prot.find('[name^="id"]').attr("value", id);
        prot.find('[name^="name"]').attr('name', 'name[' + id + ']');
        prot.find('[name^="col3"]').attr('name', 'col3[' + id + ']');
        prot.find('[name^="col4"]').attr('name', 'col4[' + id + ']');
        $(form).find("tbody").append(prot);
     
        setupFormValidation(form);
        return false;
    });

    We shouldn't need much in the remove function either. Since all of the code deciding about the number of rows has been moved out, the remove function becomes nice and small indeed.

    Code javascript:
    // Remove button functionality
    $("table.dynatable button.remove").live("click", function() {
        var form = this.form;
     
        $(this).parents("tr").remove();
        setupFormValidation(form);
    });

    Here's the full code from my working example:

    Code javascript:
    <html> 
    	<head> 
    		<base href="http://183.78.169.54/v3/dynamicrow.php">
            <script src="http://code.jquery.com/jquery-1.5.1.min.js"></script> 
    		<script src="jquery.validate.js"></script> 
    		<script> 
    		$(document).ready(function() {
                function setupSingleRowValidation(form) {
                    function filledFields(array) {
                        // when given ['name', 'age'] this function will return the following string
                        // '[name="name"]:filled, [name="age"]:filled'
                        var selectors = [];
                        $(array).each(function (i, name) {
                            selectors.push('[name="' + name + '"]:filled');
                        });
                        return selectors.join(', ');
                    }
                    function createSingleRowRule(field) {
                        var suffix = /\[.*\]/.exec(field),
                            name = 'name' + suffix,
                            col3 = 'col3' + suffix,
                            col4 = 'col4' + suffix;
                        return {
                            required: filledFields([name, col3, col4]),
                            number: (field === col3)
                        };
                    }
     
                    // clean up pre-existing rules before adding new ones
                    $('tr td:not(:first) input', form).each(function () {
                        if ($(this.form).validate().currentElements.has(this).length) {
                            $(this).rules('remove');
                        }
     
                        var rule = createSingleRowRule(this.name);
                        $(this).rules('add', rule);
                    });
     
                    // prepare single row rules
                    var nameField = $('tr td input[name^="name"]', form);
                    //var singleRowRules = createSingleRowRules(nameField.attr('name'));
     
                    // initialize validation with single row rules
                    $(form).validate({
                        singleRowRules
                    });
                }
    			function setupMultipleRowValidation(form) {
                    // clean up fields so that they contain the multiple row validation rules
                    /*$(form).validate().currentElements.each(function () {
                        $(this).rules('remove');
                    });*/
     
                    $('td:not(:first) input', form).each(function () {
                        $(this).rules('add', {required: true});
                    });
                    $('[name^="col3"]', form).each(function () {
                        $(this).rules('add', {number: true});
                    });
                };
                function setupFormValidation(form) {
                    if ($('tbody tr', form).length > 1) {
                        setupMultipleRowValidation(form);
                    } else {
                        $(form).validate().resetForm();
                        setupSingleRowValidation(form);
                    }
                }
     
                var form = $("#form1");
                setupFormValidation(form);
     
    			var prot = $('tr.prototype').clone().removeClass('prototype');
    		    $(form).data('prototype', prot);
     
                var id = 0;
     
    			// Add button functionality
    			$("table.dynatable button.add").click(function() {
    				var form = this.form;
    				id++;
     
    				// Get a new row based on the prototype row
    				var prot = $(form).data('prototype').clone();
    				prot.find('[name^="id"]').attr("value", id);
                    prot.find('[name^="name"]').attr('name', 'name[' + id + ']');
                    prot.find('[name^="col3"]').attr('name', 'col3[' + id + ']');
                    prot.find('[name^="col4"]').attr('name', 'col4[' + id + ']');
    				$(form).find("tbody").append(prot);
     
                    setupFormValidation(form);
    				return false;
    			});
     
    			// Remove button functionality
    			$("table.dynatable button.remove").live("click", function() {
    				var form = this.form;
     
                    $(this).parents("tr").remove();
                    setupFormValidation(form);
    			});
     
    			jQuery('.dOnly').live('keyup', function () 
    			{     
    				 this.value = this.value.replace(/[^0-9\.]/g,''); 
    			});
            });
    		</script> 
    		<style> 
    			.dynatable {
    				border: solid 1px #000; 
    				border-collapse: collapse;
    			}
    			.dynatable th,
    			.dynatable td {
    				background-color:#ccc; 
    				font-size:14px;
    				font-color:#ffffff;
    				font-family:Calibri;
    			}
    			.dynatable .prototype {
     
    			}
    			label.error 
    			{ display: block; }
     
    			td { vertical-align: top; }
     
    		</style> 
    	</head> 
    	<body> 
    		<form action="" method="post" name="form1" enctype="multipart/form-data" id=form1 > 
    		<table class="dynatable"> 
    			<thead> 
    				<tr> 
    					<th>ID</th> 
    					<th>Name</th> 
    					<th>Col 3</th> 
    					<th>Col 4</th> 
    					<th><button class="add">Add</button></th> 
    				</tr> 
    			</thead> 
    			<tbody> 
    				<tr class="prototype"> 
    					<td><input type="text" name="id[]" value="0" /></td> 
    					<td><input type="text" name="name[]" /></td> 
    					<td><input type="text" name="col3[]" /></td> 
    					<td><input type="text" name="col4[]" /></td> 
    					<td><button class="remove">Remove</button> 
    				</tr> 
     
    		</table> 
    		<input class="buttons" type="Submit" name="Submit" value="Submit"> 
    	</form> 
    	</body> 
    </html>
    Last edited by paul_wilkins; Mar 31, 2011 at 16:13.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  20. #70
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    You are really great it works. Now I want to learn so I am new so some of my question maybe too simple for you. Let me ask you some basic stuff. Please correct me if I am wrong. Ok first when the start of form you check is there any row or not. Then setupFormValidation is used to set the rules accordingly correct? What is this line doing $('tr td:notfirst) input', form).each(function () {" what is the not first means? Is it means not the first row is it? Why do we check when we know only left with one single row right? I have more question will ask later once I clarify one by one.

  21. #71
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    What is this line doing $('tr td:notfirst) input', form).each(function () {" what is the not first means? Is it means not the first row is it?
    Not quite. It's on the td so it's not the first column, that being the id column.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  22. #72
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    So exactly what is this code representing then. Then what is this doing if ($(this.form).validate().currentElements.has(this).length) { immediately after that.

  23. #73
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Dear Paul,
    So exactly what is this code representing then. Then what is this doing if ($(this.form).validate().currentElements.has(this).length) { immediately after that.
    Ahh yes, that was a part of some post-midnight coding, at around 3am. It's pretty good though. Let's break it down.

    Here's the section of code that it's in, so that you can see the context in which it is used.

    Code javascript:
    // clean up pre-existing rules before adding new ones
    $('tr td:not(:first) input', form).each(function () {
        if (if ($(this.form).validate().currentElements.has(this).length) {
            $(this).rules('remove');
        }
        var rule = createSingleRowRule(this.name);
        $(this).rules('add', rule);
    });

    The problem being solved, is when transitioning from the multiple row rules over to the single row rules.

    You cannot just add the single row rules to the form, because the multiple row rules won't be replaced. They would stay there too, which is not what we want.

    Looking at the problem from a high level, we want to remove the validation rules from form fields, so that we can then add a different set of validation rules to them.

    If we try to remove rules from an element that has no rules on it (which happens the first time we load the page, for example) the validate function throws an error.

    That means the process that needs to take place on each field is:
    1. Check if the field has any existing validation rules
    2. If it has rules, remove them
    3. Add the new rules that apply to the field

    This line of code is the magic that checks if any of the existing validation rules are for the field being processed:

    Code javascript:
    if ($(this.form).validate().currentElements.has(this).length) {

    The different parts of it are:
    • The validator is accessed via the .validate() object
    • The validator object provides a list of the current form elements in the currentElements property, which is a jQuery object.
    • The .has(this) checks if the field we're currently checking is in that list. jQuery then returns back another jQuery object with any matching fields
    • Finally, we get the length of that jQuery object, which tells us if the field we are currently checking has any rules applied to it.


    That line of code might be easier to understand if it were moved in to a separate function, for example:

    Code javascript:
    function hasExistingRules(field) {
        var fieldsWithRules = $(this.form).validate().currentElements,
            matchingFields = fieldsWithRules.has(field);
        return matchingFields.length > 0;
    }
    ...
    if (hasExistingRules(this)) {
        ...
    }
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  24. #74
    SitePoint Guru
    Join Date
    Feb 2007
    Posts
    874
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dear Paul,
    Can you disect this part for me I dont quite understand $('tr td:notfirst) input', form).each(function () ? I know is something to do with tr and td. What is the not first?

  25. #75
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by newtomysql View Post
    Dear Paul,
    Can you disect this part for me I dont quite understand $('tr td:notfirst) input', form).each(function () ? I know is something to do with tr and td. What is the not first?
    Sure thing. Working backwards through the selector can be the best way to understand them.

    Code:
    $('tr td:not(:first) input', form)
    It searches from the form, for inputs that are not in the first td.

    No hang on, it will only rule out the first of all the td's. It won't rule out the first td of other rows. It won't affect the running of the script, but that doesn't mean that it should be left there.

    To rule out the first td of each row means doing something a bit more complex, and it's not quite as flexible. Still, you an use this instead:

    Code javascript:
    $('td input:not([name^="id"])', form).each(function () {

    Which says:

    • In the form
    • Get inputs where their name does not start with id
    • Which are within the td elements
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •