Django动态表单集:为新增输入元素递增ID以实现全局Ajax自动补全
我懂你的痛点——现在只有第一个author输入框能触发自动补全,因为你给所有字段都用了同一个txtSearch ID(HTML里ID必须唯一,jQuery只会给第一个匹配到的元素绑定事件),而且新增的动态表单行里的输入框没有被绑定事件。下面给你几个简单可行的解决方案,按推荐度排序:
方案1:使用类选择器+事件委托(最推荐)
这个方法能完美处理动态新增的表单元素,不管你是手动添加行还是用工具库,都能生效。
步骤1:修改forms.py,替换ID为类
把原来固定的id: 'txtSearch'换成一个类名,比如author-autocomplete:
AuthorFormset = modelformset_factory( Author, fields=('due_date','author' ), extra=5, widgets={ 'due_date': forms.DateInput(attrs={ 'class': 'form-control', 'placeholder': 'Date' }), 'author': forms.TextInput(attrs={ 'class': 'form-control author-autocomplete', # 这里替换为类 'placeholder': 'Participants' }), } )
步骤2:修改JavaScript,用事件委托绑定自动补全
因为动态新增的元素不会在页面加载时存在,所以我们需要用事件委托,监听父容器(或者document)下所有匹配类的元素的焦点事件,再绑定自动补全:
$(document).ready(function(){ // 事件委托:监听所有.author-autocomplete元素的focus事件 $(document).on('focus', '.author-autocomplete', function() { // 避免重复绑定,先检查是否已初始化 if (!$(this).data('autocomplete')) { $(this).autocomplete({ source: "/ajax_calls/search/", minLength: 2, open: function(){ setTimeout(function () { $('.ui-autocomplete').css('z-index', 99); }, 0); } }); } }); });
这里加了!$(this).data('autocomplete')的判断,是为了避免同一个输入框多次绑定自动补全事件,防止出现异常。
方案2:利用Django Formset自动生成的字段ID/Name
Django的ModelFormset会自动给每个字段的ID和Name加上索引(比如第一个是id_form-0-author,第二个是id_form-1-author),我们可以直接通过属性选择器匹配这些字段:
步骤1:移除forms.py中的手动ID设置
'author': forms.TextInput(attrs={ 'class': 'form-control', 'placeholder': 'Participants' }),
步骤2:修改JavaScript,匹配所有包含author的输入框
$(document).ready(function(){ $(document).on('focus', 'input[name*="author"]', function() { if (!$(this).data('autocomplete')) { $(this).autocomplete({ source: "/ajax_calls/search/", minLength: 2, open: function(){ setTimeout(function () { $('.ui-autocomplete').css('z-index', 99); }, 0); } }); } }); });
input[name*="author"]会匹配所有name属性包含author的输入框,刚好覆盖formset里的所有author字段。
方案3:监听Formset新增事件(适用于使用动态Formset库的场景)
如果你用了django-dynamic-formset这类库来实现表单行的动态添加,可以直接监听它的added事件,在新行添加后立即绑定自动补全:
$(document).ready(function(){ // 先给页面加载时存在的字段绑定自动补全 $('.author-autocomplete').autocomplete({ source: "/ajax_calls/search/", minLength: 2, open: function(){ setTimeout(function () { $('.ui-autocomplete').css('z-index', 99); }, 0); } }); // 监听动态表单的新增事件 $('.form-row').formset({ added: function(row) { // 给新行里的author字段绑定自动补全 row.find('.author-autocomplete').autocomplete({ source: "/ajax_calls/search/", minLength: 2, open: function(){ setTimeout(function () { $('.ui-autocomplete').css('z-index', 99); }, 0); } }); } }); });
不管选哪个方案,都能让所有动态新增的author字段都触发自动补全功能,你可以根据自己的项目情况选择最合适的~
内容的提问来源于stack exchange,提问作者Chirag Sharma

