Flask框架Jinja2循环渲染删除模态框始终指向首元素问题
问题原因
核心是违反了HTML id 属性全局唯一的规则:你在{% for %}循环里给每一行的删除确认模态框都设置了相同的idexampleModal,浏览器只会识别DOM中第一个匹配该id的元素,所以不管点击哪一行的删除按钮,触发的永远是第一条数据绑定的模态框,和Jinja2循环渲染逻辑无关。
另外你的HTML结构存在语法错误:模态框<div>被错误嵌套在表格行<tr>内部,且{% endfor %}位置放在了</tr>闭合标签之前,生成的DOM结构不合法,也会导致渲染行为异常。
修复方案
两种方案按需选择即可:
方案1:给每个模态框分配唯一id(改动最小,适合数据量小的场景)
- 将每一行模态框的id绑定当前文档的
_id值,保证全局唯一 - 修改删除按钮的
data-target属性,精准匹配当前行对应的模态框id - 调整标签闭合位置,把
</tr>移到{% endfor %}前面,保证表格结构合法
修改后的核心代码片段:
<tbody> {% for doc in docs %} <tr> <td class="text-center"><a href="./done?_id={{ doc['_id'] }}"><input type="image" src="static/images/recipe.png" width="30"></a></td> <td class="text-center"><font size ="8"><em>{{ doc["clientId"] }}</em></font></td> <td class="text-center"><strong>{{ doc["version"] }}</strong></td> <td class="text-center"><strong>{{ doc["description"] }}</strong></td> <td class="text-center"><strong>{{ doc["lastUpdate"] }}</strong></td> <td class="text-center"><img src="{{ url_for('static',filename='images/trash.png') }}" width="30" data-toggle="modal" data-target="#deleteModal_{{ doc['_id'] }}" />{{ doc["_id"] }}</td> <td class="text-center"><a href="./showRec?_id={{ doc['_id'] }}" target="_blank"> <img src="{{ url_for('static',filename='images/view_n.png') }}" width="30" /></a> </td> <td class="text-center"><a href="./cloneRec?_id={{ doc['_id'] }}"> <img src="{{ url_for('static',filename='images/edit.png') }}" width="30" /></a> </td> </tr> <!-- 模态框移到tr外部,id绑定唯一文档标识 --> <div class="modal fade" id="deleteModal_{{ doc['_id'] }}" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel_{{ doc['_id'] }}" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="deleteModalLabel_{{ doc['_id'] }}">Delete action</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> Delete {{ doc["_id"] }} ? </div> <div class="modal-footer"> <a href="./delete?_id={{ doc['_id'] }}"><button type="button" class="btn btn-danger">OK</button></a> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> </div> </div> </div> </div> {% endfor %} </tbody>
方案2:单模态框动态传值(性能更好,适合列表数据量大的场景)
如果列表条目多,循环生成大量模态框会抬升页面体积,这时候只需要保留一个全局模态框,点击删除时通过JS动态注入当前文档参数即可:
- 把模态框整体移到for循环外部、页面底部位置,全局只保留一份
- 给删除按钮加自定义属性存储当前行的文档id
- 加少量JS监听模态框弹出事件,动态替换模态框内显示的文档id和删除跳转链接
核心代码示例:
<!-- 表格内删除按钮修改 --> <td class="text-center"> <img src="{{ url_for('static',filename='images/trash.png') }}" width="30" data-toggle="modal" data-target="#deleteModal" data-docid="{{ doc['_id'] }}" /> {{ doc["_id"] }} </td> <!-- 循环结束后放置唯一的全局模态框 --> <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="deleteModalLabel">Delete action</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> Delete <span id="deleteDocId"></span> ? </div> <div class="modal-footer"> <a href="" id="deleteConfirmBtn"><button type="button" class="btn btn-danger">OK</button></a> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> </div> </div> </div> </div> <!-- JS动态赋值逻辑 --> <script> $('#deleteModal').on('show.bs.modal', function (event) { var triggerBtn = $(event.relatedTarget) var docId = triggerBtn.data('docid') var modal = $(this) modal.find('#deleteDocId').text(docId) modal.find('#deleteConfirmBtn').attr('href', './delete?_id=' + docId) }) </script>
额外说明
原代码标签属性后多了不少无意义的逗号、右括号(比如src="xxx" , width="30" )这类写法),虽然多数浏览器会自动容错,但建议清理掉,避免不必要的兼容问题。
内容的提问来源于stack exchange,提问作者Flora
相关产品推荐
相关产品推荐

