克隆jQuery UI日期选择器时出现问题

21

我有一个div,里面有一个日期选择器。我使用以下代码进行克隆:

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();

这是我代码的简化版。它能正常工作,日历显示在预期位置,但当日期被点击时,之前的一个日期选择器的值会更新..(即来自它克隆的日期选择器)。

我尝试过像这样先销毁(不存在的)实例:

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

没什么运气...

我已经检查了它如何跟踪实例并手动清除了数据,代码如下:

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

依然没有运气。

我不明白的是,只有日期选择行为存在问题,其他一切都按预期工作。

现在真的不知道还要检查什么了..

12个回答

43

对我来说,这个方法与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();

请查看http://jsbin.com/ahoqa3/2以获得一个快速演示。

顺便说一下,您在问题的代码中似乎有不同的错误。CSS类应为hasDatepicker而不是hadDatepicker,同时您有时写作mydiv,而变量的下一次写作是myDiv,这并不相同。


2
太好了。我知道这已经过时了,但是今天早上我遇到了这个问题,这个答案解决了我的问题,我把它变成了一个小函数,可以在需要的地方重复使用: function initialiseDates() { $('.datePicker').each(function () { $(this).removeClass('hasDatepicker').removeData('datepicker').unbind().datepicker({ dateFormat: 'dd/mm/yy' }); ; }); }; 完美,谢谢! :D - Jamie Hartnoll
做得不错。但是如果您克隆表单的整行(例如邀请人员数据),该行可能包含其他输入字段,这些字段可能具有不同的输入数据验证器,我们不希望失去它们。在这种情况下,您应该销毁 myDiv 上的日期选择器并进行克隆(true),然后再为 myDiv 初始化日期选择器。在初始化 newDiv 上的日期选择器之前,请清除其 id .attr("id", "")。这对我很有帮助。 - Pavel K
跟进@JamieHartnoll的评论:如果你有两个字段需要克隆并使用类,对我来说秘诀是循环遍历代码块的新克隆;然后对每个元素执行$(this).removeData('datepicker').unbind().datepicker({format:'yourformathere'}); - pjammer

27

问题是这样的。datepicker在初始化时为它绑定的输入字段创建基于UUID的ID属性。你克隆这些元素会导致更多具有相同ID(jQuery不喜欢)或者具有不同ID(如果你的克隆例程管理那样,那么datepicker就不知道这些克隆)。换句话说,datepicker仅在调用它的时间初始化与您选择器匹配的所有元素。当您可以将init调用包装在用于创建克隆体的任何函数中时,尝试一遍又一遍地销毁/禁用/启用实际上没有意义。

由于我的克隆函数通常从隐藏的DOM元素而不是可见元素中复制,因此我可以自行决定是在克隆之前还是之后进行绑定。所以,在你的页面上将#templateDiv设置为一个隐藏元素,并且已经有INPUT元素在其中。

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();
}

这就是全部的内容了。尽可能在能够使用Clone(true)的时候使用它,长远来看这将为您节省不少麻烦。


8
如果在克隆之前调用.datepicker('destroy').removeAttr('id'),然后重新初始化日期选择器,它就能正常工作。
这似乎是destroy的一个bug,因为它应该将元素返回到原始状态。

这个问题困扰了我好几天。我本来可以添加日期选择器,但是在第二行之后就无法正常工作,因为“id”始终相同。通过添加removeAttr('id')解决了这个问题。谢谢!@dfmiller - Aris

5

只需做

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

在克隆 div 元素之前。 然后在插入克隆元素后,再次绑定日期选择器。

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

这种方法有点“hacky”,但是它完美地解决了问题。


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

它的工作很好。

但是仅仅这样做,日期选择器会在克隆的输入框上打开,并将日期设置为原始输入框(因为它们具有相同的ID)。

为了解决这个问题,您必须更改克隆输入框的ID属性。

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

而且它将会非常好用!


1

以下是我的操作步骤:

首先,您需要从克隆元素中删除类hasDatepickerfrom,因为这是导致日期选择器无法附加到特定元素的原因。

然后,您需要删除每个克隆元素的id属性,否则 .datepicker() 将认为已将日期选择器添加到此元素。

之后,在克隆元素上调用 .datepicker()。

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

0

这是适合我的完整解决方案。

//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"});

还有HTML的td表格。

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

希望这能对你有所帮助。
祝你有美好的一天。

0

改变顺序怎么样?

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();

说实话,我不知道datepicker内部是如何工作的。我的直觉是它会在jQuery DOM存储中存储一些东西。让我们尽可能避免复制它。
(在这些代码行之间,您可能有很长的业务逻辑。重点是在将datepicker放在#someDiv上之前备份#someDiv。)

这是我的问题...假设我有两个带有复杂动态表单的表格行。有一个“+”按钮,当点击它时,会复制最后一行的DOM并将其插入到该行之后。因此,第一个日期选择器必须首先启用,而第二个可能启用也可能不启用。 - h3.
像这样...但带有日期选择器。 - h3.
@h3: 我仍然不明白为什么你不能复制一个干净的 someDiv。备份不必插入到 DOM 中... - pestaa
@h3 理解起来有些困难。1. 在你的DOM中有一个#someDiv。2. 你正在创建它的一个副本并存储在一个变量中。3. 将一个日期选择器附加到其中一个子节点。4. 在插入之前,必要时再次克隆干净的div。5. 插入后,日期选择器像往常一样被附加。-- 从这里开始,只有步骤4和5重复。 - pestaa
@h3那就很奇怪了。你能否向后退一步,使用jQuery本身或通过Ajax在服务器端动态构建DOM? - pestaa
显示剩余3条评论

0

确保您新克隆的日期选择器具有不同的名称和ID,而不是与原始选择器相同。如果它们都具有相同的名称,则您所描述的行为将是正常的。

尝试将最后一行更改为类似以下内容的内容:

newDiv.find('input.datefield').attr('id', 'newDatePicker').attr('name', 'newDatePicker').datepicker();

更有可能的是他有关联的类,只是为了展示而给我们提供了一个ID。 - pestaa

0
这可能有点晚了,但是上面的所有建议对我都没有用,我想出了一个简单的解决方案。
首先,问题的原因是什么: JQuery将datepicker分配给元素ID。如果您克隆元素,则相同的ID也可能被克隆。这是jQuery不喜欢的。您可能会遇到空引用错误或无论单击哪个输入字段,日期都被分配给第一个输入字段。
解决方案:
1)销毁datepicker 2)为所有输入字段分配新的唯一ID 3)为每个输入字段分配datepicker 确保您的输入类似于此。
<input type="text" name="ndate[]" id="date1" class="n1datepicker">

在克隆之前,销毁日期选择器

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

克隆之后,还需要添加这些行

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

魔法就在这里发生了


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接