dousuie2222
2013-12-29 15:25
浏览 81
已采纳

jquery嵌套表单克隆

I am extremely new to jquery and I've been doing a lot of research in trying to clone a nested fieldset, at least I think that's what its called. I have a very simple form that has the following:

 Group - input box
 People
 ====================================
 FirstName LastName
 ====================================
 input box input box 

I want to be able to add some controls that can do the following, one would be to be able to add more people within that group, so lets say I wanted to add 3 more fields to Group it would look like this:

 Group - input box
 People
 ====================================
 FirstName  LastName
 ====================================
 input box  input box
 input box  input box Delete
 input box  input box Delete
 input box  input box Delete

 And then if I wanted to add a new Group it would look something like this:

 Group - input box
 People
 ====================================
 FirstName  LastName
 ====================================
 input box input box
 input box input box Delete
 input box input box Delete
 input box input box Delete


 Group - input box Delete Group
 People
 ====================================
 FirstName LastName
 ====================================
 input box input box

Does anyone have any simple way of doing this? I have found a few plugins like sheepit and some other ones, but they are very complicated to use and to modify to fit for what I want to do. Any help would be very much appreciated

This is the code i have so far, although it doesn't really work. I wanted to show what i have tried so far.

 <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Intranet</title>
  <link rel="stylesheet" href="../css/style.css">
<script type="text/javascript" src="../scripts/jquery-1.4.2.js"></script>

<script>
var current = 1;

$(function() {

  $('.addPerson').click(function() {
        current++;
var strToAdd = '<p><label for="firstname"'+current+'">Name</label><em>*</em><input id="firstname'+current+'" name="firstname'+current+'" size="25" /><input id="lastname'+current+'" name="lastname'+current+'" size="25"/></p>'
    $('#mainPeople').append(strToAdd)
  })

})

</script>
</head>

<body>

<form id="someform" method="post">
    <fieldset id="mainGroup">
    <p>Area:
    <label for="Group1">Group</label>
        <em>*</em><input id="Group1" name="Group1" size="25" />
    </p>
    <fieldset id="mainPeople">
        <p>
        <label for="firstname1">Name</label>
        <em>*</em><input id="firstname1" name="firstname1" size="25"/> <input id="lastname1" name="lastname1" size="25" />
        </p>
    </fieldset>
    </fieldset>
    <p>
    <input type="button" id="addPerson" value="Add Another Person">
    <input type="button" id="addGroup" value="Add Another Group">
    </p>

    <input type="submit" value="Save">
</form>

</body>
</html>
  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doubi1713 2013-12-31 02:23
    已采纳

    Getting into JQuery makes things really easy. Just practice 'til it sticks!
    If you're new to JQuery, it's worth looking through the API docs. It really helps you get started.

    Anyway. After reading your question, I decided to challenge myself and speed-create a small plugin per your request, mostly for funsies, but also because I've been there.

    Clocked it at ~2 hrs (including tea break).
    It may be a tad inefficient, but it works. That's all that matters, right?
    ...I hope I'm not coming across as a smug bastard that you want to punch in the face; I'm actually terrible and need the practice >.<

    Hopefully you'll find some use for it, or at least learn something from it.
    Let me explain my approach for building stuff * ahem *


    It is generally a good idea to have an outline or an idea of what needs to be done before making, well, anything. Writing comments that outline some basic things you need to do really help and speeds the process.

    My outlines for making the plugin were something like

    • Settings for class names, input size, prefixes and delimiters for input names
    • Template functions that build and return elements (easier to handle)
    • Update the form inputs with new ids and names after something is removed or added
    • Make sure it's relatively easy to parse on the server side once you submit the form
    • Have some plugin functions to make it easier to add/edit/remove stuff
    • Double -- quintuple -- check that everything works as expected (code self-QA; good practice)

    Code | JSFiddle

    Here is the plugin code, I named it GroupManager
    (don't judge me, I'm terrible with names)

    Javascript

    (function($){
        $.fn.GroupManager = function(opts) {
            //Self reference, for when you're deep in the darkness and need a light
            var _self = this;
    
            //Defaults
            var def = {
                sDelimeter: "_",
                sGroupPrefix: "g",
                sFirstNamePrefix: "fn",
                sLastNamePrefix: "ln",
                iInputSize: 25,
                clContainer: "group_container",
                clTable: "person_table",
                clTitle: "group_title",
                clTitleInput: "group_title_input",
                clDelBtn: "del_btn",
                sDelGroupTitle: "Remove group",
                sDelPersonTitle: "Remove person from this group",
                sAddPersonTitle: "Add a person to group",
                clAddBtn: "add_btn",
                clFirstName: "fname",
                clLastName: "lname",
                clPersonMenu: "menu"
            };
    
            //Extend option properties to defaults
            $.extend(def, opts);
    
            //Template to create a new group
            function tmpl_group_table(grp_name){ 
                var container = $("<div>"),
                    group_ttl = $("<div>"),
                    group_field = $("<fieldset>"),
                    group_table = $("<table>"),
                    group_title_input = $("<input>");
    
                container.addClass(def.clContainer);
    
                //Add the group title label & input
                group_title_input.addClass(def.clTitleInput);
    
                //If a group name was provided, set its value as well
                if(grp_name) group_title_input.val(grp_name);
    
                group_ttl.addClass(def.clTitle);
                group_ttl.append("<label>Group - </label>");
                group_ttl.append(group_title_input);
    
                //Set up the table
                group_table.addClass(def.clTable);
                group_table.append("<caption>People in this group:</caption>");
                group_table.append("<thead><tr><th>First name</th><th>Last Name</th><th>&nbsp;</th><tr></thead>");
                group_table.append("<tbody></tbody>");
                group_table.append(tmpl_person_row(false));
    
                //Link elements
                group_field.append(group_table);
                container.append(group_ttl);
                container.append(group_field);
    
                return container;
            }
    
            //Function that creates a new person row in table
            function tmpl_person_row(btn){
                var row = $("<tr>"),
                    col1 = $("<td>"), i1 = $("<input>"),
                    col2 = $("<td>"), i2 = $("<input>"),
                    col3 = $("<td>");
    
                //Set up input for first name
                i1.addClass(def.clFirstName);
                i1.attr("size", def.iInputSize);
                col1.append(i1);
    
                //Set up input for last name
                i2.addClass(def.clLastName);
                i2.attr("size", def.iInputSize);
                col2.append(i2);
    
                //Make a delete button, if specified
                if(btn){
                    var del_btn = $("<div>");
    
                    del_btn.text("x");
                    del_btn.addClass(def.clDelBtn);
                    del_btn.attr("title", def.sDelPersonTitle);
                    del_btn.click(function(){
                        var grp = $(this).parents("."+def.clContainer);
                        $(this).closest("tr").remove();
                        reassign(grp);
                    });
                    col3.append(del_btn);
                }else{
                    col3.html("&nbsp;");
                }
                col3.addClass(def.clPersonMenu);
    
                //Link elements to row
                row.append([col1, col2, col3]);
    
                return row;
            }
    
            //Function that reassigns input ids and names, usually called after something was removed
            function reassign(group){
                var ind = group.index() + 1,
                    id = def.sGroupPrefix + def.sDelimeter + ind,
                    title_input = group.find("."+def.clTitleInput),
                    title_label = title_input.siblings("label"),
                    p_table = group.find("." + def.clTable);
    
                title_label.attr("for", id);
                title_input.attr({id: id, name: id});
    
                p_table.find("tbody tr").each(function(i, e){
                    var fname_id = def.sFirstNamePrefix + def.sDelimeter + ind + def.sDelimeter + (i+1),
                        lname_id = def.sLastNamePrefix + def.sDelimeter + ind + def.sDelimeter + (i+1);
    
                    $(e).find("."+def.clFirstName).attr({id: fname_id, name: fname_id});
                    $(e).find("."+def.clLastName).attr({id: lname_id, name: lname_id});
                });
            }
    
            //Add a person to the specified group (0-based index)
            this.addPerson = function(group_no, first_name, last_name){
                var grp = _self.find("."+def.clContainer).eq(group_no),
                    persons = grp.find("."+def.clTable).find("tbody"),
                    row = tmpl_person_row(true);
    
                if(first_name) $("."+def.clFirstName, row).val(first_name);
                if(last_name) $("."+def.clLastName, row).val(last_name);
    
                persons.append(row);
                reassign(grp);
            };
    
            //Set a person's first and last name
            this.setPerson = function(group_no, person_no, first_name, last_name){
                var grp = _self.find("."+def.clContainer).eq(group_no),
                    row = grp.find("tbody tr").eq(person_no);
    
                if(first_name) $("."+def.clFirstName, row).val(first_name);
                if(last_name) $("."+def.clLastName, row).val(last_name);
            };
    
            //Add a bunch of people to the specified group, assuming an array with arrays that hold two strings
            this.addPeople = function(group_no, arr){
                var grp = _self.find("."+def.clContainer).eq(group_no),
                    rows = grp.find("tbody tr");
    
                if(arr.length > rows.length){
                    //Add more rows until it matches array length
                    for(var i = 0; i < (arr.length - rows.length); i++){
                        _self.addPerson(group_no);
                    }
    
                    reassign(grp);
                    rows = grp.find("tbody tr");
                }
    
                for(var j = 0; j < arr.length; j++){
                    var row = rows.eq(j);
                    $("."+def.clFirstName, row).val(arr[j][0]);
                    $("."+def.clLastName, row).val(arr[j][4]);
                }
            };
    
            //Add a group to the form. Can provide title and an array with people to populate it from the start
            this.addGroup = function(title, arr){
                var grp = tmpl_group_table(title);
                _self.append(grp);
    
                if(arr){
                    _self.addPeople(grp.index(), arr);
                }
    
                //Add a remove group button if it's not the first group
                if(grp.index() !== 0){
                    var del_btn = $("<div>");
    
                    del_btn.text("x");
                    del_btn.addClass(def.clDelBtn);
                    del_btn.attr("title", def.sDelGroupTitle);
    
                    grp.find("."+def.clTitle).append(del_btn);
                    del_btn.click(function(){
                        $(this).parents("."+def.clContainer).remove();
                        _self.refresh();
                    });
                }
    
                //Add an "add people"-button
                var add_people_btn = $("<div>");
                add_people_btn.text("+");
                add_people_btn.addClass(def.clAddBtn);
                add_people_btn.attr("title", def.sAddPersonTitle);
                add_people_btn.click(function(){
                    _self.addPerson(grp.index());
    
                });
                grp.find("."+def.clTable+" caption").append(add_people_btn);
    
                reassign(grp);
            };
    
            //Remove a group
            this.removeGroup = function(group_no){
                var grp = _self.find("."+def.clContainer).eq((group_no));
                grp.remove();
                _self.refresh();
            };
    
            //Refresh form
            this.refresh = function(){
                _self.find("."+def.clContainer).each(function(){ reassign($(this));});
            };
    
            //Add an empty group
            _self.addGroup();
    
            return this;
        }; 
    }(jQuery));
    
    $(function(){
        //Create an instance for the empty form
        var gm = $("#someform").GroupManager();
    
        //Add groups filled with a title and people
        var unknowns = [
            ["John", "Doe"], 
            ["Mary", "Jane"], 
            ["Tom", "Harry"]
        ];
    
        var randoms = [
            ["Looney", "McFloo"], 
            ["Private", "Detective"], 
            ["Tom", "Jones"],
            ["Rick", "James"]
        ];
    
        gm.addGroup("Unknowns", unknowns);
        gm.addGroup("Randoms", randoms);
    
        //Attach click handlers for the main menu
        $("#add_group").click(function(){ gm.addGroup();});
        $("#save_form").click(function(e){ e.preventDefault(); console.log($("#someform").serialize());});
    });
    

    HTML

    <div id='menu'>
        <button id='add_group' type="button">Add group</button>
        <button id='save_form' type="button">Save</button>
    </div>
    
    <form id="someform" method="post" action="#"></form>
    

    CSS

    body{ margin: 0; padding: 0 20px; font-family: Arial, Helvetica, sans-serif;}
    
    #menu{
        margin-bottom: 20px;
    }
    
    #save_form{
        margin-left: 25px;
    }
    
    .group_container{
        margin-bottom: 20px;
        border: 1px solid gray;
        float: left;
        clear: both;
    }
    
    .group_title{
        text-align: left;
        border-bottom: 1px solid lightgray;
        margin: 0 10px;
        padding-left: 10px;
    }
    
    .group_title_input{
        width: 150px;
        border: 0;
        text-align: left;
        text-overflow: ellipsis;
        font-weight: bold;
    }
    
    .del_btn, .add_btn{
        color: red;
        cursor: pointer;
        text-align: center;
        display: inline-block;
        border: 1px solid transparent;
        height: 16px;
        width: 16px;
        line-height: 16px;
        float: right;
    }
    
    .add_btn{
        color: green;
        float: right;
        font-size: 1.25em;
        line-height: 1.25em;  
    }
    
    .del_btn:hover, .add_btn:hover{
        border-color: lightgray;
    }
    
    .del_btn:active, .add_btn:active{
        color: white;
        background-color: black;
    
    }
    
    .person_table caption{
        margin-bottom: 10px;
        font-size: 0.75em;
        text-align: left;
        font-style: italic;
    }
    
    .person_table input{
        text-align: left;
        font-size: 0.833em;
    }
    
    .group_container{
        font-size: 14px;
    }
    
    .person_table{
        border-collapse: collapse;
    }
    
    .person_table thead th:not(:nth-child(3)){
        font-size: 0.833em;
        border-bottom: 1px solid black;
        font-weight: normal;
        text-align: center;
    }
    
    .person_table tbody td:nth-child(3){
        width: 30px;
    }
    
    .group_container fieldset{
        border: 0px;
    }
    
    .groups, .persons{
        border: 1px solid gray;
        padding: 4px;
    }
    
    .fname, .lname{
        width: 100px;
    }
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题