21

I have a div in which there is a datepicker. I use something like this to clone it:

mydiv = $('#someDiv');

// works fine so far
mydiv.find('input.datefield').datepicker();

// clone without the events and insert
newDiv = myDiv.clone(false).insertAfter(myDiv);

// datepicker won't re-init if this class is present
newDiv.find('.hadDatepicker').removeClass('hadDatepicker');

// reinitialize datepicker
newDiv.find('input.datefield').datepicker();

This is a stripped down version of my code. It works and the calendar shows up as expected where it is expected .. but when a date is clicked, the previous datepicker's value gets updated.. (the one from which it was cloned).

I've tried to destroy the (inexisting) instance before like this:

newDiv.find('input.datefield').datepicker('destroy').datepicker();

No luck ..

I've checked how it keeps track of instances and manually cleared the data like this:

newDiv.find('input.datefield').data('datepicker', false).datepicker('destroy').datepicker();

Still no luck.

What I don't understand is that only the date selection behavior is buggy, everything else works as expected.

I really don't know what else to check now ..

h3.
  • 10,688
  • 15
  • 51
  • 54

12 Answers12

43

This works for me with jQuery UI 1.7.2

var mydiv = $('#someDiv');
mydiv.find('input.datefield').datepicker();
var newDiv = mydiv.clone(false).attr("id", "someDiv2").insertAfter(mydiv);
newDiv.find('input.datefield')
  .attr("id", "")
  .removeClass('hasDatepicker')
  .removeData('datepicker')
  .unbind()
  .datepicker();

Check http://jsbin.com/ahoqa3/2 for a quick demo

btw. you seem to have different errors in the code of your question. The css class is hasDatepicker not hadDatepicker and at one time you wrote mydiv and the next time the variable is myDiv which isn't the same.

jitter
  • 53,475
  • 11
  • 111
  • 124
  • 2
    Excellent. I know this is ages old, but this answer cured the problem when I came across it this morning, I've turned it into a little function which I can reuse wherever needed: `function initialiseDates() { $('.datePicker').each(function () { $(this).removeClass('hasDatepicker').removeData('datepicker').unbind().datepicker({ dateFormat: 'dd/mm/yy' }); ; }); };` Perfect, thanks! :D – Jamie Hartnoll Feb 13 '12 at 10:49
  • Good work. But if you clone the whole row of a form (for example invited people data), row may contain another input fields, which may have different input data validators, which we don't wanna loose. In this case you should destroy datepicker on myDiv and make clone(true), then init datepicker again for myDiv. Before initialization datepicker on newDiv, clear its id .attr("id", ""). It helped me. – Pavel K Jan 05 '13 at 12:52
  • Following up on the @JamieHartnoll comment: If you have 2 fields you are cloning and using classes, the secret sauce for me was to loop through the new clone of your chunk of code; then go through each and `$(this).removeData('datepicker').unbind().datepicker({format:'yourformathere'});` – pjammer Oct 26 '15 at 10:36
27

Here's the problem. datepicker creates UUID-based ID attributes for the input fields it binds when you initialize it. You cloning those elements results in more elements with either the same ID (which jQuery does not like) or a different ID if your clone routine manages that (which means datepicker does not know about the clones). In other words, datepicker only initializes all the elements matching your selector at the time you call it. it actually makes less sense to try to destroy/disable/enable over and over, when you can just wrap the init call inside whatever function you use to create the clones.

Because my clone functions typically copy from hidden DOM elements rather than visible ones, I have the luxury deciding whether I need to bind before or after cloning. So, make #templateDiv a hidden element on your page with the INPUT element already in there.

mydiv = $('#templateDiv');
mydest = $('#someDiv');

function make_the_donuts() {
    newDiv = myDiv.clone(true).insertAfter(mydest);  
    // attach datepickers by instance rather than by class
    newDiv.find('input.datefield').datepicker();
}

and that pretty much does it. Clone(true) whenever you can, it'll save you headaches in the long run.

Andrew Roazen
  • 511
  • 4
  • 4
8

If you call .datepicker('destroy').removeAttr('id') before cloning and then re-init the date picker it will work.

This seems to be a bug with destroy since it is supposed to return the element back to it's original state.

Alfred
  • 21,058
  • 61
  • 167
  • 249
dfmiller
  • 1,103
  • 12
  • 17
  • this has been bugging me for days. I could add datepickers, but was not working for after the second row, because 'id' was always the same. by adding removeAttr('id') it fixed it. thans! @dfmiller – Aris Mar 10 '13 at 09:09
5

just do

$('input.datefield').datepicker("destroy");

before cloning the div. Then after inserting the clone bind the datepicker again

$('input.datefield').datepicker();

kind of a 'hacky' solution but it works perfectly.

edfuh
  • 490
  • 5
  • 6
2
$('input.datefield').datepicker("destroy");
$('input.datefield').datepicker();

it works good. But just doing this, datepicker will open on cloned input and set the date to the original input (because they have the same ID)

to solve this you must change id attribute of the cloned input.

dp = < cloned input >
var d = $('input.vDateField');
dp.removeClass('hasDatepicker');
dp.attr('id', dp.attr('id')+d.length);
d.datepicker("destroy");
d.datepicker();

and it will work great!

Alfred
  • 21,058
  • 61
  • 167
  • 249
kuhn
  • 176
  • 3
  • 5
1

Here how it worked for me:

First you need to remove the class hasDatepickerfrom the cloned elements,because this is what is preventing the datepicker from getting attached to the specific element.

Then you gotta remove the id attribute from each of the cloned elements else .datepicker() will assume that datepicker is added to this element.

After that call .datepicker() on cloned element.

newDiv.find('.classAttributeGivenForDatepicker').each(function() {
   $(this).removeAttr('id').removeClass('hasDatepicker');
   $(this).datepicker({dateFormat: 'dd-mm-yy', minDate: 0, autoclose: true,});
});
Hardik Patil
  • 515
  • 1
  • 4
  • 16
0

The complete solution that works for me.

//before
$('input.fecha').datepicker("destroy");
newcell.innerHTML = table.rows[0].cells[i].innerHTML;
//change de input id
$("input.fecha").attr("id", function (arr) {return "fecha" + arr;});
//after
$('input.fecha').datepicker({defaultDate: "+1w",changeMonth: true,numberOfMonths: 1, showOn: "button", buttonImage: "<?php echo base_url() ?>images/calendar.gif", buttonImageOnly: true, showLabel:false, dateFormat:"yy-mm-dd"});

And the html td table.

<td><?php echo form_input(array('name' => 'fecha','id' => 'fecha','class' => 'fecha')); ?></td>

Hope this helps you.

Good day

mariofertc
  • 383
  • 2
  • 7
0
var dt = new Date();
var month = dt.getMonth();
var day = dt.getDate();
var year = dt.getFullYear()-5;
            $newClone.children().children("#fna"+clickID)
    .attr({
        'id': 'fna1'+newID,
        'name': 'fna'+newID,
        'value': day + '-' + month + '-' + year
    })
    .datepicker("destroy")
    .datepicker({
        firstDay: 1, 
        changeMonth: true, 
        changeYear: true,
        yearRange: 'c-100:c',
        defaultDate: '-1y',
        dateFormat: 'dd-mm-yy' ,
        nextText: "Mes siguiente",
        prevText: "Mes anterior",
        monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'],
        dayNamesMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa']
    });
fancyPants
  • 50,732
  • 33
  • 89
  • 96
Isaac
  • 11
  • 2
    plz use only ENGLISH as your language, not any other. – anuj arora Dec 19 '12 at 09:45
  • I mean, there is no rule about what language you can speak... Yes, programing is ENGLISH only BUT variables name can be in any language...at the end it is only a string! – Maduro Mar 27 '17 at 16:52
0

This might be a little late, but all the suggestions above didn't work for me, I came up with an easy solution for this.

First, what is causing the problem: JQuery assign datepicker to element id. if you are cloning element, then same id might be cloned as well. which jQuery doesn't like. You might end up with either receiving null reference error or the date being assigned to first input field regardless which input field you click on.

Solution:

1) destroy datepicker 2) assign new unique ids to all input field 3) assign datepicker for each input

Make sure your input is something like this

<input type="text" name="ndate[]" id="date1" class="n1datepicker">

Before you clone, destroy datepicker

$('.n1datepicker').datepicker('destroy');

After you clone, add these lines as well

var i = 0;
$('.n1datepicker').each(function () {
    $(this).attr("id",'date' + i).datepicker();
    i++;
});

and the magic happens

EGN
  • 2,480
  • 4
  • 26
  • 39
0

What about changing the order?

mydiv = $('#someDiv');

// clone without the events and insert
newDiv = myDiv.clone(false).insertAfter(myDiv);

// datepicker won't re-init if this class is present
// not necessary anymore
// newDiv.find('.hadDatepicker').removeClass('hadDatepicker');

newDiv.find('input.datefield').datepicker();

// datepicker attached as a last step
mydiv.find('input.datefield').datepicker();

Honestly I don't know how datepicker works internally. My hunch is that it stores something in jQuery DOM storage. Let's avoid copying it at all costs.

(You might have long business logic between these lines of code. The point is to have a backup of #someDiv before putting a datepicker on it.)

pestaa
  • 4,749
  • 2
  • 23
  • 32
  • this is my problem .. let's say I have 2 tables rows with complex dynamic forms in them. There is a "+" button that when clicked copy the last row's DOM and insert it back after that last row. So the first datepicker *has* to be enabled first and the second might or might not get enabled.. – h3. Mar 14 '10 at 03:38
  • http://vonautomatisch.at/media/uploads/grappelli/inlinetabular_big.jpg Like this .. but with datepickers. – h3. Mar 14 '10 at 03:40
  • @h3: I still don't understand why you couldn't make a copy of a clean someDiv. The backup doesn't have to be inserted to the DOM... – pestaa Mar 14 '10 at 03:42
  • Just tried it .. I clone(false) the DOM structure and use it. So the DOM I'm using has never been initialized .. and I still get the same problem. Now I'm *really* confused.. – h3. Mar 14 '10 at 04:22
  • @h3 Having tough time to understand you. 1. You have a #someDiv in your DOM. 2. You're making a copy of it and store in a variable. 3. Attach a datepicker to a child node. 4. When required, clone the clean div *again* before inserting it. 5. After inserted, the datepicker is attached as usual. -- From this point, only step 4 and 5 repeats. – pestaa Mar 14 '10 at 04:34
  • Sorry I speak French, I might have explained myself badly. But what you described is exactly what I tried and it doesn't work. The problem seems to really be with the datepicker because both solutions worked with other plugins .. – h3. Mar 14 '10 at 05:30
  • @h3 It is really weird then. Can you make a step back and build up the DOM on-the-fly either with jQuery itself or server-side through Ajax? – pestaa Mar 14 '10 at 13:09
  • No .. the form is created from the database, so the dom is totally dynamic. In fact the only thing I think might work is to convert the DOM fragment to string and then turn it bak to DOM with jQUery .. – h3. Mar 14 '10 at 15:24
0

Make sure your newly cloned datepicker has a different name and ID than the original. If they both have the same name, then the behavior you're describing would be normal.

Try changing that last line to something like:

newDiv.find('input.datefield').attr('id', 'newDatePicker').attr('name', 'newDatePicker').datepicker();
David Morton
  • 16,338
  • 3
  • 63
  • 73
  • More likely he has classes associated, just provided us an ID for the sake of presentation. – pestaa Mar 14 '10 at 04:30
0

Datepicker doesn't if the ID of an element is changed. So, it is better not to change the id of a element if it is must required. But if you really needs to change the ID and that changed id needs to work with datepicker then follow it:

$(selector).removeClass('hasDatepicker');
$(selector).datepicker({
  changeMonth: true,
  changeYear: true
});
Mahbub Alam
  • 368
  • 2
  • 6