我找到了解决上述问题的有效方法。这与jquery.formset.js 的工作方式有关。万一其他人撞到了这块砖头,这就是我修复它的方法。
当您单击“添加项目”时,jquery.formset.js 知道包含您最初显示的表单集表单的容器。然后它遵循这个算法:
- 克隆其中一个表单集表单
- 将其添加到最后一个表单集表单容器之后的 DOM
- 重新计算并更改
id、name等属性
- 等
另一方面,flexselect.js 通过在 DOM 中查找指定的 select 标记并向它们添加一些数据来工作。
通过将已被操作的克隆selects 添加回 DOM 是导致意外行为的原因。
我想不出比修改jquery.formset.js 的源代码更好的办法了。我是这样改的(从第 75 行开始):
$addBtn.click(function() {
var nextIndex = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val());
var row = $('.' + options.formCssClass + ':first').clone(true).get(0);
$(row).removeAttr('id').insertAfter($('.' + options.formCssClass + ':last'));
$(row).find('input,select,textarea,label').each(function() {
updateElementIndex(this, options.prefix, nextIndex);
// If this is a checkbox or radiobutton, set uncheck it.
// Fix for Issue 1, reported by Wilson.Andrew.J:
var elem = $(this);
if (elem.is('input:checkbox') || elem.is('input:radio')) {
elem.attr('checked', false);
} else {
elem.val('');
}
});
var formCount = nextIndex + 1;
$('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount);
// If we've got more than one form, enable delete buttons:
if (formCount > 1) { $('a.' + options.deleteCssClass).show(); }
// If a post-add callback was supplied, call it with the added form:
if (options.added) options.added($(row));
return false;
});
到.....
$addBtn.click(function() {
var nextIndex = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val());
var row = $('.' + options.formCssClass + ':first').clone(true).get(0);
// formset.js does not know that the form has been manipulated by flexselect.js. By cloning the form as
// it is, it clones elements that have already had events and stuff attached to them. This is what
// causes the weird behavior with flexselect.js
// first we'll remove the class and style attributes
$(row).find('select.flexselect').last().removeAttr("class style");
// next, remove the input field that was previously generated by flexselect
$(row).find('input.flexselect').remove();
$(row).removeAttr('id').insertAfter($('.' + options.formCssClass + ':last'));
$(row).find('input,select,textarea,label').each(function() {
updateElementIndex(this, options.prefix, nextIndex);
// If this is a checkbox or radiobutton, set uncheck it.
// Fix for Issue 1, reported by Wilson.Andrew.J:
var elem = $(this);
if (elem.is('input:checkbox') || elem.is('input:radio')) {
elem.attr('checked', false);
} else {
elem.val('');
}
});
// At this point, formset.js has done most of the major lifting. We can now add the attributes that
// flexselect.js needs which is just a select with a CSS class called 'flexselect'.
$(row).find("select").attr("class", "flexselect");
var formCount = nextIndex + 1;
$('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount);
// If we've got more than one form, enable delete buttons:
if (formCount > 1) { $('a.' + options.deleteCssClass).show(); }
// If a post-add callback was supplied, call it with the added form:
if (options.added) options.added($(row));
return false;
});
然后我调整了初始化代码如下:
<script type="text/javascript">
jQuery(document).ready(function($) {
$("select.flexselect").flexselect();
$(".inline.{{ posting_form.prefix }}").formset({
prefix: "{{ posting_form.prefix }}",
addText: "Add item",
deleteText: "Remove",
added: function(){
$('select.flexselect').last().removeData("flexselect");
$('select.flexselect').flexselect();
},
});
});
</script>
这就是我修复它的方法。希望对其他人有所帮助。