如何成功将bootstrap日期选择器克隆到表格单元格(TD)?

时间:2015-04-03 18:55:19

标签: jquery jsp spring-mvc twitter-bootstrap-3 bootstrap-datepicker

为了说明,该表看起来像这样......

enter image description here

...请注意独立数据贴片如何弹出(它有效)......

enter image description here

...但是,当我动态尝试将相同的bootstrap datapicker html克隆到TD(表格单元格)时,它不起作用(点击不会弹出日历等)...

enter image description here

以下是定义数据贴纸的javascript ...

jq(".datepicker").datepicker(
{
        format: "yyyy/mm/dd",
        autoclose: true,
        todayHighlight: true
});

这是datepicker的html ...

<div id="clonedatepicker">
    <div class="control-group" style="max-width: 15em;">
        <div class="controls">
            <div class="input-group">
                <input id="testdatepicker" type="text" class="datepicker form-control" />
                <label for="testdatepicker" class="input-group-addon btn">
                    <span class="glyphicon glyphicon-calendar"></span>
                </label>
            </div>
        </div>
    </div>
</div>

...这是我尝试克隆datepicker背后的代码

    -
    -
    -
    //...save aside value in TD cell...
    var v = jq(this).html();

    //...clone the datepicker...
    cdp = jq("#clonedatepicker").clone(); 

    //...initialize the clone as a datepicker(?)...
    var inp = cdp.children().children().children().children().first();
    inp.datepicker(
    {
        format: "yyyy/mm/dd",
        autoclose: true,
        todayHighlight: true
    });

    //...provide unique id to datepicker widget...
    var sib = inp.next();
    var id = createId();
    inp.prop("id", id);
    sib.prop("for",id);


    //...set input value to what was in TD/cell...
    inp.val(v);

    //...empty TD...
    jq(this).empty();

    //...insert datepicker widget...
    jq(this).html(cdp.html());
    -
    -
    -

以下是自包含“.html”文件的内容......

(将其复制到空的“.html”文件中,它将说明我正在尝试解决的问题。)


    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>Bootstrap Example</title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" media="screen">
            <link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.10.5/css/jquery.dataTables.css" media="screen">
            <link href="http://eternicode.github.io/bootstrap-datepicker/bootstrap-datepicker/css/datepicker3.css" rel="stylesheet">

            <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js""></script>
            <script type="text/javascript" src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
            <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.10.5/jquery.dataTables.min.js"></script>
            <script src="http://eternicode.github.io/bootstrap-datepicker/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>

            <script type="text/javascript">
            var jq = jQuery.noConflict();
            var $contextPath;

            function createId()
            {
                return 'DPxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {        
                    var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
                    return v.toString(16);
                });
            }

            jq(document).ready(function ()
            {
                var jq = jQuery.noConflict();

                $contextPath = jq("#contextPath").val();

                var cdp;    //clone date picker

                jq('table').click(function (e) {

                    var t = jq(e.target);
                    var tableId = jq(this).closest('table').prop('id');
                    var dt = jq(this).DataTable();
                    e.preventDefault();

                    //...collect the clicked "tag name" and use it to determine what to do...
                    var tagName = e.target.tagName;

                    if (tagName === "BUTTON")
                    {
                        if (jq(e.target).html() === 'Edit')
                        {
                            //...get list of previous "sibling" td's...
                            var editCellList = Array.prototype.reverse.call(jq(e.target).parent().prevAll()); //jq(e.target).parent().prevAll();

                            //...iterate over list and replace plain html text with "input" tag - use plain html text as initial value...                
                            editCellList.each(function (index, e)
                            {
                                if (tableId === "page0grid")
                                {
                                    if (index === 0)  // "Field A" (input)
                                    {
                                        jq(this).html("<input type='text' value='" + jq(this).html() + "' />");
                                    }
                                    else
                                    if (index === 1)  // "Field B" (datepicker)
                                    {
                                        var v = jq(this).html();
                                        cdp = jq("#clonedatepicker").clone(); 

                                        //...initialize the clone as a datepicker(?)...
                                        var inp = cdp.children().children().children().children().first();
                                        inp.datepicker(
                                        {
                                            format: "yyyy/mm/dd",
                                            autoclose: true,
                                            todayHighlight: true
                                        });

                                        //...provide unique id to datepicker widget...
                                        var sib = inp.next();
                                        var id = createId();
                                        inp.prop("id", id);
                                        sib.prop("for",id);


                                        //...set input value to what was in TD/cell...
                                        inp.val(v);

                                        //...empty TD...
                                        jq(this).empty();

                                        //...insert datepicker widget...
                                        jq(this).html(cdp.html());
                                    }                        
                                }
                            });

                            //...change/toggle the button title from "Edit" to "Save"... 
                            jq(e.target).html('Done');
                        }
                        else
                        {
                            //...change/toggle the button title from "Save" to "Edit"...                 
                            jq(e.target).html('Edit');

                            //...get list of previous "sibling" td's...                
                            var saveCellList = Array.prototype.reverse.call(jq(e.target).parent().prevAll());    //...to reverse order?...               

                            //...convert widgets back to plain text in TDs (i.e., the values)...
                            for (i = 0; i < saveCellList.length; i++)
                            {
                                var ch = jq(saveCellList[i]).children().first();

                                if (ch.prop("tagName") === "INPUT")
                                {
                                    alert("input found...val=" + ch.val());
                                    jq(saveCellList[i]).html(ch.val());
                                }
                                else
                                if (ch.prop("tagName") === "DIV")
                                {
                                    //...remove datepicker widget and leave value in TD...
                                    jq(saveCellList[i]).html(cdp.children().children().children().children().first().val());
                                }                        
                                else
                                {
                                    jq(saveCellList[i]).html(ch.children().first().html());
                                }
                            }

                            //...iterate over list and save changes to datatables object...    
                            var ri = jq(e.target).closest("tr").index();

                            for (i = 0; i < saveCellList.length; i++)
                            {
                                var cv = jq(saveCellList[i]).html();
                                dt.cell(ri, i + 1).data(cv);
                            }

                            jq(this).DataTable().draw();
                        }
                    }
                });


                jq("#submitForm").click(function ()
                {
                    var page0griddata = JSON.stringify(page0grid.rows().data().toArray());
                    console.log("would be submitting the following table data...:" + page0griddata);
                });


                //var data=[["id"="0", "fieldAStrg"="XXX0", "fieldBStrg"="2015-04-03"], ["id"="1", "fieldAStrg"="XXX1", "fieldBStrg"="2015-04-03"]];

                var data= [{id:0, fieldAStrg:"XXX0", fieldBStrg:"2015-04-03"}, {id:"1", fieldAStrg:"XXX1", fieldBStrg:"2015-04-03"}];
                console.log(data);    

                var page0grid = jq('#page0grid').DataTable({
                    //"ajax": $contextPath + "/page0/testGridList",
                    "data" : data,
                    "columns": [
                        {"title": "ID",      "data": "id", "visible": false},
                        {"title": "Field A", "data": "fieldAStrg"},
                        {"title": "Field B", "data": "fieldBStrg"}
                    ],
                    "columnDefs": [{
                            "targets": 3,
                            "data": null,
                            "defaultContent": "<button class='edit'>Edit</button>"
                        }],
                    "info": false,
                    "searching": false,
                    "bPaginate": false,
                    //"scrollY": 600, <== hides dropdown list overflow...
                    "bLengthChange": false,
                    "bScrollCollapse": true,
                    "autoWidth": true,
                    "order": [[0, 'desc']],
                    "bSort": false
                });

                jq('#addNew').click(function ()
                {
                    var buttonTitleArray = jq('#page0grid tbody > tr > td > button').map(function () {
                        return jq(this).html();
                    }).get();

                    if (jq.inArray("Done", buttonTitleArray) === -1)
                    {
                        var rowIndex = jq('#page0grid tbody > tr').length;
                        console.log("row index(?)...:[" + rowIndex + "]");

                        var rowNode = page0grid.row.add(
                                {
                                    "id": "", //NEW" + jq.now(),
                                    "fieldAStrg": "",
                                    "fieldBStrg": ""
                                }, rowIndex).draw().node();

                        console.log("addNew...row data at index rowIndex=" + page0grid.cell(rowIndex, 0).data());

                        jq(rowNode).find("button").trigger("click");
                    }
                });

                jq(".datepicker").datepicker(
                {
                        format: "yyyy/mm/dd",
                        autoclose: true,
                        todayHighlight: true
                });
            });
          </script>
        </head>
        <body>
            <div class='panel panel-primary' id="page0gridpaneldiv" style="z-index: 0; overflow: visible;">
                <div class='panel-heading'>
                    <h6 class='panel-title'>page0grid</h6>
                </div>    
                <div class='panel-body table-responsive' id="page0gridtablediv" style="padding:0; z-index: 0; overflow: visible;">    
                    <table class="table table-striped table-hover" id="page0grid" style="z-index: 0; overflow: visible;"></table>
                </div>
            </div>         

            <button type="button" id="addNew" class="btn btn-primary">Add New</button>
            <button type="button" id="submitForm" class="btn btn-default">submit form - post grid data</button>

            <br/>
            <br/>    

            <div id="clonedatepicker">
                <div class="control-group" style="max-width: 15em;">
                    <div class="controls">
                        <div class="input-group">
                            <input id="testdatepicker" type="text" class="datepicker form-control" value=""/>
                            <label for="testdatepicker" class="input-group-addon btn">
                                <span class="glyphicon glyphicon-calendar"></span>
                            </label>
                        </div>
                    </div>
                </div>
            </div>
        </body>
    </html>

1 个答案:

答案 0 :(得分:0)

经过一番研究,以下是我的解决方案......

(注意:主要观点来自于2012年10月发布的答案[并且显然在很大程度上被忽略]被另一个StackOverflow成员回答类似[现已结束]问题 - 请参阅:Jquery UI Datepicker don't work after clone element)... - “Sushanth在我看来,s是 的答案 - 虽然它获得了零(0)票......直到现在...... - 因为我刚投了票)

解决方案中的主要修改是......

改变了这一点:

    -
    -
    -        

    if (index === 1)  // "Field B" (datepicker)
    {
        var v = jq(this).html();
        cdp = jq("#clonedatepicker").clone(); 

        //...initialize the clone as a datepicker(?)...
        var inp = cdp.children().children().children().children().first();
        inp.datepicker(
        {
            format: "yyyy/mm/dd",
            autoclose: true,
            todayHighlight: true
        });

        //...provide unique id to datepicker widget...
        var sib = inp.next();
        var id = createId();
        inp.prop("id", id);
        sib.prop("for",id);


        //...set input value to what was in TD/cell...
        inp.val(v);

        //...empty TD...
        jq(this).empty();

        //...insert datepicker widget...
        jq(this).html(cdp.html());
    }      

    -
    -
    -      

对此:

    -
    -
    -        
    if (index === 1)  // "Field B" (datepicker)
    {
        var v = jq(this).html();
        cdp = jq("#clonedatepicker").clone(true);

        //...initialize the clone as a datepicker(?)...
        var inp = cdp.children().children().children().children().first();

        //...set input value to what was in TD/cell...
        inp.val(v);

        //...empty TD...
        jq(this).empty();

        //...insert datepicker widget...
        jq(this).html(cdp.html());
    }

    -
    -
    -        

改变了这一点:

    -
    -
    -        

    jq(".datepicker").datepicker(
    {
            format: "yyyy/mm/dd",
            autoclose: true,
            todayHighlight: true
    });

    -
    -
    -   

对此(被掠夺的部分):

    -
    -
    -        

    jq('body').on('click', '.datepicker', function () {
        jq(this).datepicker(
        {
            format: "yyyy/mm/dd",
            autoclose: true,
            todayHighlight: true
        }).focus();
    });  

    -
    -
    -              

下面是整个html和javascript(单个可运行的HTML页面),如果有兴趣...


    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>Bootstrap Example</title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" media="screen">
            <link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.10.5/css/jquery.dataTables.css" media="screen">
            <link href="http://eternicode.github.io/bootstrap-datepicker/bootstrap-datepicker/css/datepicker3.css" rel="stylesheet">
            <style type="text/css">

            </style>
            <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js"></script>
            <script type="text/javascript" src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
            <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.10.5/jquery.dataTables.min.js"></script>
            <script src="http://eternicode.github.io/bootstrap-datepicker/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>

            <script type="text/javascript">
                var jq = jQuery.noConflict();
                var $contextPath;

                jq(document).ready(function ()
                {
                    var jq = jQuery.noConflict();

                    $contextPath = jq("#contextPath").val();

                    var cdp;    //clone date picker

                    jq('table').click(function (e) {

                        var t = jq(e.target);
                        var tableId = jq(this).closest('table').prop('id');
                        var dt = jq(this).DataTable();
                        e.preventDefault();

                        //...collect the clicked "tag name" and use it to determine what to do...
                        var tagName = e.target.tagName;

                        if (tagName === "BUTTON")
                        {
                            if (jq(e.target).html() === 'Edit')
                            {
                                //...get list of previous "sibling" td's...
                                var editCellList = Array.prototype.reverse.call(jq(e.target).parent().prevAll()); //jq(e.target).parent().prevAll();

                                //...iterate over list and replace plain html text with "input" tag - use plain html text as initial value...                
                                editCellList.each(function (index, e)
                                {
                                    if (tableId === "page0grid")
                                    {
                                        if (index === 0)  // "Field A" (input)
                                        {
                                            jq(this).html("<input type='text' value='" + jq(this).html() + "' />");
                                        }
                                        else
                                        if (index === 1)  // "Field B" (datepicker)
                                        {
                                            var v = jq(this).html();
                                            cdp = jq("#clonedatepicker").clone(true);

                                            //...initialize the clone as a datepicker(?)...
                                            var inp = cdp.children().children().children().children().first();

                                            //...set input value to what was in TD/cell...
                                            inp.val(v);

                                            //...empty TD...
                                            jq(this).empty();

                                            //...insert datepicker widget...
                                            jq(this).html(cdp.html());
                                        }
                                    }
                                });

                                //...change/toggle the button title from "Edit" to "Save"... 
                                jq(e.target).html('Done');
                            }
                            else
                            {
                                //...change/toggle the button title from "Save" to "Edit"...                 
                                jq(e.target).html('Edit');

                                //...get list of previous "sibling" td's...                
                                var saveCellList = Array.prototype.reverse.call(jq(e.target).parent().prevAll());    //...to reverse order?...               

                                //...convert widgets back to plain text in TDs (i.e., the values)...
                                for (i = 0; i < saveCellList.length; i++)
                                {
                                    var ch = jq(saveCellList[i]).children().first();

                                    if (ch.prop("tagName") === "INPUT")
                                    {
                                        jq(saveCellList[i]).html(ch.val());
                                    }
                                    else
                                    if (ch.prop("tagName") === "DIV")
                                    {
                                        jq(saveCellList[i]).html(ch.children().children().children().first().val());
                                    }
                                    else
                                    {
                                        jq(saveCellList[i]).html(ch.children().first().html());
                                    }
                                }

                                //...iterate over list and save changes to datatables object...    
                                var ri = jq(e.target).closest("tr").index();

                                for (i = 0; i < saveCellList.length; i++)
                                {
                                    var cv = jq(saveCellList[i]).html();
                                    dt.cell(ri, i + 1).data(cv);
                                }

                                jq(this).DataTable().draw();
                            }
                        }
                    });


                    jq("#submitForm").click(function ()
                    {
                        var page0griddata = JSON.stringify(page0grid.rows().data().toArray());
                        console.log("would be submitting the following table data...:" + page0griddata);
                        alert("page0griddata=" + page0griddata);
                    });


                    //var data=[["id"="0", "fieldAStrg"="XXX0", "fieldBStrg"="2015-04-03"], ["id"="1", "fieldAStrg"="XXX1", "fieldBStrg"="2015-04-03"]];

                    var data = [{id: 0, fieldAStrg: "XXX0", fieldBStrg: "2015-04-03"}, {id: "1", fieldAStrg: "XXX1", fieldBStrg: "2015-04-03"}];
                    console.log(data);

                    var page0grid = jq('#page0grid').DataTable({
                        //"ajax": $contextPath + "/page0/testGridList",
                        "data": data,
                        "columns": [
                            {"title": "ID", "data": "id", "visible": false},
                            {"title": "Field A", "data": "fieldAStrg"},
                            {"title": "Field B", "data": "fieldBStrg"}
                        ],
                        "columnDefs": [{
                                "targets": 3,
                                "data": null,
                                "defaultContent": "<button class='edit'>Edit</button>"
                            }],
                        "info": false,
                        "searching": false,
                        "bPaginate": false,
                        //"scrollY": 600, <== hides dropdown list overflow...
                        "bLengthChange": false,
                        "bScrollCollapse": true,
                        "autoWidth": true,
                        "order": [[0, 'desc']],
                        "bSort": false
                    });

                    jq('#addNew').click(function ()
                    {
                        var buttonTitleArray = jq('#page0grid tbody > tr > td > button').map(function () {
                            return jq(this).html();
                        }).get();

                        if (jq.inArray("Done", buttonTitleArray) === -1)
                        {
                            var rowIndex = jq('#page0grid tbody > tr').length;
                            console.log("row index(?)...:[" + rowIndex + "]");

                            var rowNode = page0grid.row.add(
                                    {
                                        "id": "", //NEW" + jq.now(),
                                        "fieldAStrg": "",
                                        "fieldBStrg": ""
                                    }, rowIndex).draw().node();

                            console.log("addNew...row data at index rowIndex=" + page0grid.cell(rowIndex, 0).data());

                            jq(rowNode).find("button").trigger("click");
                        }
                    });

                    jq('body').on('click', '.datepicker', function () {
                        jq(this).datepicker(
                        {
                            format: "yyyy/mm/dd",
                            autoclose: true,
                            todayHighlight: true
                        }).focus();
                    });

                });
            </script>
        </head>
        <body>
            <div class='panel panel-primary' id="page0gridpaneldiv" style="z-index: 0; overflow: visible;">
                <div class='panel-heading'>
                    <h6 class='panel-title'>page0grid</h6>
                </div>    
                <div class='panel-body table-responsive' id="page0gridtablediv" style="padding:0; z-index: 0; overflow: visible;">    
                    <table class="table table-striped table-hover" id="page0grid" style="z-index: 0; overflow: visible;"></table>
                </div>
            </div>         

            <button type="button" id="addNew" class="btn btn-primary">Add New</button>
            <button type="button" id="submitForm" class="btn btn-default">submit form - post grid data</button>

            <br/>
            <br/>    

            <div id="clonedatepicker">
                <div class="control-group" style="max-width: 15em;">
                    <div class="controls">
                        <div class="input-group">
                            <input id="testdatepicker" type="text" class="datepicker form-control"/>
                            <label for="testdatepicker" class="input-group-addon btn">
                                <span class="glyphicon glyphicon-calendar"></span>
                            </label>
                        </div>
                    </div>
                </div>
            </div>
        </body>
    </html>