Django模板循环中AJAX仅获取首个元素ID的问题求助
问题排查结果
出现这个问题的核心原因是循环渲染时大量重复的通用类名、固定ID导致jQuery选择器全局匹配时永远命中第一条帖子对应的DOM元素,具体有3个直接诱因:
- 所有帖子的编辑弹窗都用了固定
id="edit"、相同的通用类modal-edit、textarea_edit,没有和帖子主键做唯一绑定,用$('.textarea_edit')这类全局选择器取值时,默认返回DOM树中第一个匹配的元素,也就是第一条帖子的输入框内容 - 列表里的[Edit]按钮没有绑定对应帖子弹窗的触发逻辑,原代码里a标签直接指向帖子详情页路由,没有配置data属性唤起当前帖子专属的编辑弹窗
- JS点击回调没有基于当前点击的元素做相对DOM查找,所有取值、弹窗操作都是全局匹配元素,自然永远拿到第一条的数据
修复方案
1. 修改Django模板循环代码
给每个弹窗、触发按钮绑定帖子主键做唯一标识,配置正确的弹窗触发属性,修复后代码如下:
{% for post in paginated_posts %} <div style="padding: 10px;" id="{{post.id}}"> <div style="padding: 10px; border: 1px solid;"> <p> <h4><a href="{% url 'post_view' post.pk %}">{{ post.title }}</a></h4> </p> <p style="display: inline-flex;"> {% if post.author.profile.id %} by: <span style="font-weight: bold;"><a href="{% url 'profile_class' post.author.profile.id %}"> {{ post.author }} </a></span> {% else %} by: <span style="font-weight: bold;"> {{ post.author }} </span> {% endif %} on {{ post.creation_date }} </p> <h5 class="card-text post-object-content{{post.id}}">{{ post.post_text }}</h5> <!-- Edit --> {% if user.is_authenticated %} {% if user.id == post.author.id %} <!-- Button modal edit 新增弹窗触发属性,绑定对应帖子的唯一弹窗ID --> <small><a href="javascript:void(0)" data-toggle="modal" data-target="#edit-{{ post.pk }}">[Edit]</a></small> <!-- Modal EDIT 给弹窗ID加post主键后缀,保证唯一 --> <div class="modal fade modal-edit" id="edit-{{ post.pk }}" role="dialog"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content new-post-content"> <div class="modal-header"> <h5 class="modal-title">Edit post {{ post.id }}</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <form method=post action="{% url 'edit' post.pk %}"> {% csrf_token %} <textarea rows="10" class="form-control textarea_edit textarea-edit-{{ post.pk }}" name="textarea">{{post.post_text}}</textarea> <br> <div class="modal-footer"> <button class="btn btn-primary save editfunction" data-post_pk="{{ post.pk }}" type="submit" value="Save">Submit</button> </div> </form> </div> </div> </div> </div> {% endif %} {% endif %} </div> </div> {% endfor %}
注意:原模板代码末尾少了两个
{% endif %}和对应div闭合标签,上面代码已经补全,否则Django模板渲染会报错。
2. 修改JS逻辑
所有元素查找都基于当前点击的按钮做相对定位,不要用全局选择器直接搜通用类名,修复后代码如下:
//Edit $('.editfunction').click(function(e){ e.preventDefault() // 先拿到当前按钮所属的弹窗DOM const currentModal = $(this).closest('.modal-edit'); var post_pk = $(this).data("post_pk"); // 从当前弹窗里找输入框取值,不会拿到其他帖子的内容 var content = currentModal.find('.textarea_edit').val(); $.ajax({ type: "POST", url: `/post/${post_pk}/edit`, data: { csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value, post_id: post_pk, textarea: content }, success: function(data) { // 只关闭当前操作的弹窗 currentModal.modal('hide') // 更新对应帖子的展示内容 $(`.post-object-content${post_pk}`).html(content) } }) })
验证点
改完后可以先在浏览器右键检查元素,确认每个帖子的编辑弹窗ID都带不同的post主键,点击[Edit]按钮唤起的是当前帖子对应的弹窗,提交时可以在浏览器控制台Network面板看请求参数里的textarea值是不是当前编辑的内容即可。
内容的提问来源于stack exchange,提问作者CVilla90
相关产品推荐
相关产品推荐

