简体   繁体   中英

JQuery - cloning datepicker and select2

I asked a similar question yesterday, but after a few additions, things seem to have gone pear shaped. I have some HTML which takes the following form

<div class="form-group">
    <div class="row">
        <div class="col-md-12">
            <div class="col-md-12">
                <table class="table table-bordered" id="actionTable">
                    <tbody>
                    <tr id='actionRow1'>
                        <td>
                          <input type="text" name='actionInput[0][action]' id="actionInput"  placeholder='Action' class="form-control"/>
                        </td>
                        <td>
                          <select class="responsibility" name='actionInput[0][responsibility]' id="responsibilityInput">
                                <option value="One">One</option>
                                <option value="Two">Two</option>
                                <option value="Three">Three</option>
                            </select>
                        </td>
                        <td>
                          <input type="text" name='actionInput[0][deliveryDate]' id="dateInput" placeholder='Completion Date' class="form-control dateControl"/>
                        </td>
                      </tr>
                    </tbody>
                </table>
                <a id="add_row" class="btn btn-default pull-right">Add Row</a>
                <a id='delete_row' class="pull-right btn btn-default">Delete Row</a>
            </div>
        </div>
    </div>
</div>

So it has a text input, a select, and another text for the date. The names for the input are a 2D array because I need to handle this data in a specific way later.

Anyways, when an Add Row button is clicked, it should clone the whole tr. This includes destroying the select2 and datepicker, as well as updating the names and id's of the new inputs. To do this, I have the following JS

$(function() {
    $('#add_row').on('click', function(evt){addRow();});
    $('#delete_row').on('click', function(evt){deleteRow();});
});

function addRow() {

    $("table tr#actionRow1").eq(0).clone().each(function(tr_idx, tr_elem) {

        $(".dateControl").datepicker("destroy");

        $(".responsibility").select2("destroy");

        var
            $tr = $(tr_elem),
            newRowIdx = $("table tr").length;

        $tr.attr('id', 'actionRow' + newRowIdx);

        $tr.find("input, select").each(function(i_idx, i_elem) {

            var $input = $(i_elem);

            if($input.attr('id') == 'actionInput') {
                $(this).val("");
            }

            if ($input.hasClass('dateControl')) {
                $(this).val("");
            }

            $input.attr({
                'id': function(_, id) {
                    return id + newRowIdx;
                },
                'name': function(_, id) {
                    return id.replace('[0]', '['+ newRowIdx +']');
                },
                'value': ''
            });
        });

        $(".dateControl").datepicker({
            dateFormat: "dd-mm-yy"
        });

        $(".responsibility").select2({
            tags: true
        });

    }).appendTo("table");
}

function deleteRow() {
    curRowIdx = $("table tr").length;
    if (curRowIdx > 1) {
        $("#actionRow" + (curRowIdx - 1)).remove();
        curRowIdx--;
    }
}

I have set up the following JSFiddle to demonstrate.

In the Fiddle, I have had to comment out the destroy methods otherwise it throws an error. First problem, on first visit, the datepicker and select2 are not working. When you click Add Row, the previous rows datepicker and select2 then works, but the new one does not. So it is sort of delayed. Once you start adding multiple rows, it decides to add multiple select boxes in some of the rows. Not too sure why this is happening.

Any advice in sorting this out much appreciated.

Thanks

Calling $(".dateControl").datepicker(); will attempt to initialise a datepicker widget on all elements matching ".dateControl" currently in the DOM. Thus on the first click you'd initialise it on the first row (but NOT on the one you're cloning, since it hasn't been appended yet!). The third row added then re-initialises the datepicker on the first row and initialises it on the second, etc. Same for the other widget. You should restrict the matcher to only the row you're currently working on:

$(".dateControl", $tr).datepicker({
  dateFormat: "dd-mm-yy"
});

$(".responsibility", $tr).select2({
  tags: true
});

You don't need the destroy calls at all if you do this. Also, make sure you call these for the first row explicitly (see NicolasR's comment)


Also, the datepicker creates a new table element, so you need to target your own table everywhere you use the table selector. Otherwise the addRow function will stop working correctly after the first time you open a datepicker (which is when the new table is appended to the DOM, and the "table" selector in the appendTo line starts matching it): https://jsfiddle.net/r94pkLLb/3/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM