Search code examples
jqueryjquery-validateclone

How can I clone a fieldset without keeping the rules of the fields?


I cloned my fieldset and it works perfect. I clear all fields value perfectly. The only issue I'm having is the rules follow if submit had been hit before adding the new fieldset and no if you haven't hit on submit. What I really want is to be able to either remove all the rules and set it up again or keep the rules in a way they work properly. I tried to remove the rules and it didn't work (). I tried adding new rules, it works but I have 1 more rule for each field every time I add a section. Note that my IDs and Names changed every time I add a new fieldset.

Here is my html @Sparky:

            <!------  Fiedlset company information starts here     ------>


                <fieldset class="clonableId" id="location1">

                    <table>

                        <tr class="align_error">

                            <td>

                                <p><label id="lblOwner1" for="propertyOwner1" class="required" >Property Owner</label></p>

                            </td>

                            <td>

                                <p><input type="text" name="propertyOwner1" id="propertyOwner1" /></p>

                            </td>

                        </tr>

                    </table>

                    <p><label><strong>Excavation Address (Rural Areas Province DIrections)</strong></label></p>

                    <table>

                        <tr class="align_error">

                            <td>

                                <p><label id="lblexcavAddress1" for="excavAddress1" class="required" >Address</label> &nbsp; &nbsp;</p>

                            </td>

                            <td>

                                <p><input class="address" type="text" name="excavAddress1" id="excavAddress1" /></p>

                            </td>

                            <td>

                                <p><label id="lblexcavCity1" for="excavCity1" class="required" >City</label></p>

                            </td>

                            <td>

                                <p><input type="text" name="excavCity1" id="excavCity1" /></p>

                            </td>

                            <td><p><label id="lblexcavProv1" for="excavProv1" class="required" >Province</label></p>

                            </td>

                            <td><p>

                                <select id="excavProv1" name="excavProv1" >

                                    <option></option>

                                    <option>AB</option>

                                    <option>BC</option>

                                    <option>MB</option>

                                    <option>NB</option> 

                                    <option>NF</option>

                                    <option>NW</option>

                                    <option>NS</option>

                                    <option>NU</option>

                                    <option>ON</option>

                                    <option>PE</option>

                                    <option>QU</option>

                                    <option>SK</option>

                                    <option>YK</option>

                                </select>

                            </p></td>

                            <td><p><label id="lblzipCode1" for="excavPostCod1" class="required" >Postal Code</label></p></td>

                            <td>
                                <p><input type="text" name="excavPostCod1" id="excavPostCod1" class="lilfield55" onchange="postCod()" /></p>
                            </td>

                        </tr>

                    </table>


                </fieldset>

                <div id="newLoc">

                    <input type="button" id="addSection" value="Add new Location"> <input type="button" id="btnDel" value="remove Location above">

                </div>

                <div>

                    <input class="buttons" type="button" value="Print" onClick="window.print()" /><input id="submit_btn" class="buttons" type="submit" value="Submit" />

                </div>
                <div>

                    <button class="remove-rule">remove rule</button>

                </div>
            <!------  Fieldset Hearing conservation program ends here     ------>

        </form>

Check my Jquery out and any help will be appreciated:

$(document).ready(function(){

        $("#excavationform").validate({

                rules: 
                    {
                    compName: {
                        required: true
                    },
                    compCity: {
                        required: true,
                    },                              
                    compAddress: {
                        required: true
                    },
                    compPROV: {
                        required: true
                    },
                    compPostCod:{
                        required:true
                    }
                },

                messages: {
                        compName: "Enter the company name.",
                        compAddress: "Enter the company's address",
                        compCity: "Enter the company city",
                        compPROV: "Enter the company province",
                        compPostCod:{
                                postalcode: "Enter a valid postal code in the format A1A 1A1 (including the space).",
                                required: "A valid postal code is required"
                        }
                }

        });

        nameFields("#compName");

        nameFields("#compAddress");

        nameFields("#compCity");

        filterInvalidHHTPPostChar("#compAddress");

        filterInvalidHHTPPostChar("#compPostCod");

        makeCaps("#compPostCod");


//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////

});

$(function () {
    $("form").on("click","#addSection",function (e) {
        e.preventDefault();
        var num     = $('.clonableId').length, // how many "duplicatable" input fields we currently have
            newNum  = new Number(num + 1),      // the numeric ID of the new input field being added
            newElem = $('#location' + num).clone(true).attr('id', 'location' + newNum).fadeIn('slow'); // create the new element via clone(), and manipulate it's ID using newNum value
    // manipulate the name/id values of the input inside the new element

        // Property Owner - Input
        newElem.find('#lblOwner' + num).attr('id', 'lblOwner'+ newNum).attr('for', 'propertyOwner'+ newNum);
        newElem.find('#propertyOwner' + num).attr('id', 'propertyOwner'+ newNum).attr('name', 'propertyOwner'+ newNum).val('');

        // Excavation Address - Input
        newElem.find('#lblexcavAddress' + num).attr('id', 'lblexcavAddress' + newNum).attr('for', 'excavAddress' + newNum);
        newElem.find('#excavAddress' + num).attr('id', 'excavAddress' + newNum).attr('name', 'excavAddress' + newNum).val('');

        // Excavation City - Input
        newElem.find('#lblexcavCity' + num).attr('id', 'lblexcavCity' + newNum).attr('for', 'excavCity' + newNum);
        newElem.find('#excavCity' + num).attr('id', 'excavCity' + newNum).attr('name', 'excavCity' + newNum).val('');

        // Excavation Province - Input
        newElem.find('#lblexcavProv' + num).attr('id', 'lblexcavProv' + newNum).attr('for', 'excavProv' + newNum);
        newElem.find('#excavProv' + num).attr('id', 'excavProv' + newNum).attr('name', 'excavProv' + newNum).val('');

        // Excavation Postal Code - Input
        newElem.find('#lblzipCode' + num).attr('id', 'lblzipCode' + newNum).attr('for', 'excavPostCod' + newNum);
        newElem.find('#excavPostCod' + num).attr('id', 'excavPostCod' + newNum).attr('name', 'excavPostCod' + newNum).val('');

    // insert the new element after the last "duplicatable" input field
        $('#location' + num).after(newElem);

    // Allow the datepicker: we delete it first then we re-create it
        $('#location' + newNum).on('focus','.dateChooser', function(){
            $(this).removeClass('hasDatepicker').datepicker();
        });

    // focus on the first input of the new section
        $('#propertyOwner' + newNum).focus();

    ///////////////////////////////////////////////////////Add rules


    //////////////////////////////////////////////////Control on the new section

        nameFields("#propertyOwner" + newNum);

        nameFields("#excavAddress" + newNum);

        nameFields("#excavCity" + newNum);

        numberFields("#MBrfNumber" + newNum);

        nameFields("#supervisorName" + newNum);

        fieldLength("#propertyOwner" + newNum, 70);

        fieldLength("#excavAddress" + newNum, 70);

        fieldLength("#excavCity" + newNum, 35);

        fieldLength("#excavPostCod" + newNum, 7);

        fieldLength("#startDate" + newNum, 10);

        fieldLength("#endDate" + newNum, 10);

        fieldLength("#MBrfNumber" + newNum, 10);

        fieldLength("#supervisorName" + newNum , 70);

        /////////////////////////////////////////Dates
    // enable the "remove" button
        $('#btnDel').attr('disabled', false);

    });

    $('#btnDel').click(function () {
    // confirmation
        if (confirm("Are you sure you wish to remove this section? This cannot be undone."))
            {
                var num = $('.clonableId').length;
                // how many "duplicatable" input fields we currently have
                $('#location' + num).slideUp('slow', function () {$(this).remove();
                // if only one element remains, disable the "remove" button
                    if (num -1 === 1)
                $('#btnDel').attr('disabled', true);
                // enable the "add" button
                $('#addSection').attr('disabled', false).prop('value', "add section");});
            }
        return false;
             // remove the last element

    // enable the "add" button
        $('#addSection').attr('disabled', false);
    });

});

Solution

  • In several places you have class="required" which would be the problem had this been inside of your input elements. However, you have this class inside of your <label> elements, so we can rule that out.

    jQuery Validate needs unique name attributes on every input, so even if you accidentally duplicated the names, jQuery Validate would only work on the first instance of each element, not work on the clone... and if the element does not exist when .validate() is called, you can completely rule out the .validate() method as the cause.

    The only ways to declare rules on dynamically created elements, after .validate() is called, are as follows...

    1. using the .rules('add') method (although why would you add rules you say you don't want and I don't see this in your code)

    2. using inline HTML 5 validation attributes such as required="required". (I don't see these in your code)

    3. using inline class declarations such as class="required". (Again, you're only doing this on the <label> elements)

    In other words, I see absolutely nothing in your code that will cause any validation rules to carry over into your dynamically created, or cloned, elements. Either you've neglected to show us the code causing the problem or you are mistaken about what you're seeing.

    Inspect the DOM using your browser's developer tools and verify that the cloned markup looks like you've intended and that you don't have any attributes or classes as described in #2 and #3 above.


    If you've tried .rules('remove') and it's failed, as per documentation, this method "...manipulates only rules specified via rules-option or via rules('add')". In other words, you can only use .rules('remove') to remove rules put in place by the .validate() or .rules('add') methods.

    Keep in mind that .rules('remove') can only be attached to a selector representing a single input element...

    $('#singleInput').rules('remove');     // <- ONE input
    

    Otherwise, if your selector targets a groups of elements, you'll need to wrap it within a jQuery .each()...

    $('.groupOfInputs').each(function() {  // <- multiple inputs
        $(this).rules('remove');
    });
    

    EDIT:

    As per the jsFiddle as posted in the comments, you can see what's really happening.

    You are not having an issue with rules being cloned from the original section, and your issue really has absolutely nothing to do with rules. The issue is that you're cloning the error messages themselves... error messages only intended for the original set of elements. You really need to re-think your whole approach as I don't even understand the advantage to cloning anything here.

    Since you already go to great lengths to rename everything, simply use jQuery to write all new markup for each section rather than blindly cloning things that include dynamic content like error messages you don't even want/need. In other words, just create the new form elements with their new names, while NOT creating, cloning or copying any dynamic content from elsewhere. Your code will actually become simplified since you won't have to do so much DOM manipulation when it's being created properly in the first place.