我在模态窗口中使用 Django 表单,其中核心内容(在容器中)由 JS 生成。提交 django 模型实例保存时没有任何问题,if form.is_valid() == True模式窗口将关闭,并将焦点切换到当前背景页面。然而,if form.is_valid() == False模式内容只是在单独的 URL 中打开,并占据所有浏览器屏幕,因为视图仅呈现 .html 文件中的一小段代码。
if form.is_valid() == True
if form.is_valid() == False
目标是在出现if form_is_valid() == False表单错误时刷新当前条件下的模式窗口。
if form_is_valid() == False
模板"accounts/profile_settings.html"包含一个表单和在内部呈现的提交按钮
"accounts/profile_settings.html"
<div class="preferences_content"> {% comment %} JS generated dynamic content depends on tab pressed. {% endcomment %} </div>
我的 JS 知识非常基础,所以我很感激关于这个主题的任何建议。
The View :
def profile_update_view(request): """ Updates current Profile instance.""" if request.method == "POST": current_profile = request.user.profile profile_form = ProfileUpdateForm(request.POST, request.FILES, instance=current_profile) if profile_form.is_valid(): profile_form.save() return HttpResponseRedirect(request.META.get('HTTP_REFERER', "/")) else: profile_form = ProfileUpdateForm() return render(request, "accounts/profile_settings.html", {'profile_form': profile_form}) else: profile_form = ProfileUpdateForm() return render(request, "accounts/profile_settings.html", {'profile_form': profile_form})
document.addEventListener("DOMContentLoaded", function() { var openModalLink = document.getElementById("openPreferencesModal"); var modal = document.getElementById("preferencesModal"); var span = modal.querySelector(".close"); var preferencesContent = modal.querySelector(".preferences_content"); var tabs = modal.querySelectorAll(".tab"); openModalLink.addEventListener("click", function(event) { event.preventDefault(); modal.style.display = "block"; // Встановлюємо стиль блоку при відкритті модального вікна tabs.forEach(function(tab) { tab.classList.remove('active'); }); tabs[0].classList.add('active'); // Отримуємо url першої вкладки та завантажуємо вміст var firstTabUrl = tabs[0].getAttribute("data-url"); fetch(firstTabUrl) .then(response => response.text()) .then(data => { preferencesContent.innerHTML = data; }) .catch(error => { console.error('Error fetching content:', error); }); }); span.addEventListener("click", function() { modal.style.display = "none"; }); window.addEventListener("click", function(event) { if (event.target === modal) { modal.style.display = "none"; } }); tabs.forEach(function(tab) { tab.addEventListener("click", function(event) { event.preventDefault(); tabs.forEach(function(tab) { tab.classList.remove('active'); }); tab.classList.add('active'); var url = tab.getAttribute("data-url"); fetch(url) .then(response => response.text()) .then(data => { preferencesContent.innerHTML = data; }) .catch(error => { console.error('Error fetching content:', error); }); }); }); var editLink = modal.querySelector(".base_info a[href='']"); editLink.addEventListener("click", function(event) { event.preventDefault(); tabs.forEach(function(tab) { if (tab.getAttribute("href") === "#profile") { tab.click(); } }); }); }); {% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="preferencesModal" class="preferences_modal"> <!-- Modal content --> <div class="preferences_modal_content"> <span class="close">×</span> <section class="profile_info"> {% if user.profile.avatar %} <img src={{ user.profile.avatar.url }} alt="avatar"> {% else %} <img src={% static "img/default_profile_avatar.svg" %} alt="avatar"> {% endif %} <div class="base_info"> <span>{{ user.profile.username }}</span> <span>{{ user.email }}</span> {% if user.profile.first_name and user.profile.last_name %} <span>{{ user.profile.first_name}}, {{user.profile.last_name}}</span> {% endif %} <a href="">Edit</a> </div> </section> <section class="preferences_data"> <div class="preferences_tabs"> {% comment %} Tabs {% endcomment %} <a href="#preferences" class="tab" data-url="{% url 'preferences:preferences_update' %}">Preferences</a> <a href="#profile" class="tab" data-url="{% url 'accounts:profile_update' %}">Profile</a> </div> <div class="preferences_content"> {% comment %} JS generated dynamic content depends on tab pressed. {% endcomment %} </div> </section> </div> </div> </body> </html>
运行代码片段
您可以在 Django 视图中添加逻辑,以在表单验证失败时返回部分 HTML 内容,以便在模态窗口中动态刷新错误消息。以下是您可以采取的一种方法:
在视图中,如果表单验证失败,则将部分 HTML 内容返回到模板,以便在模态窗口中动态显示错误消息。
from django.http import JsonResponse def profile_update_view(request): """ Updates current Profile instance.""" if request.method == "POST": current_profile = request.user.profile profile_form = ProfileUpdateForm(request.POST, request.FILES, instance=current_profile) if profile_form.is_valid(): profile_form.save() return JsonResponse({'success': True}) else: # 如果表单验证失败,返回部分 HTML 内容,包含表单和错误消息 return JsonResponse({'success': False, 'html': profile_form.errors.as_ul()}) else: profile_form = ProfileUpdateForm() return render(request, "accounts/profile_settings.html", {'profile_form': profile_form})
在 JavaScript 中,如果收到表单验证失败的 JSON 响应,则使用该响应更新模态窗口中的内容,以显示错误消息。
document.addEventListener("DOMContentLoaded", function() { var openModalLink = document.getElementById("openPreferencesModal"); var modal = document.getElementById("preferencesModal"); var span = modal.querySelector(".close"); var preferencesContent = modal.querySelector(".preferences_content"); var tabs = modal.querySelectorAll(".tab"); openModalLink.addEventListener("click", function(event) { event.preventDefault(); modal.style.display = "block"; // 加载首个选项卡的内容 loadTabContent(tabs[0]); }); // 监听选项卡点击事件 tabs.forEach(function(tab) { tab.addEventListener("click", function(event) { event.preventDefault(); loadTabContent(tab); }); }); span.addEventListener("click", function() { modal.style.display = "none"; }); window.addEventListener("click", function(event) { if (event.target === modal) { modal.style.display = "none"; } }); // 加载选项卡内容 function loadTabContent(tab) { tabs.forEach(function(tab) { tab.classList.remove('active'); }); tab.classList.add('active'); var url = tab.getAttribute("data-url"); fetch(url) .then(response => response.json()) .then(data => { if (data.success) { preferencesContent.innerHTML = data.html; } else { // 如果表单验证失败,更新模态窗口内容以显示错误消息 preferencesContent.innerHTML = data.html; } }) .catch(error => { console.error('Error fetching content:', error); }); } });
在这个例子中,当表单验证失败时,后端视图返回一个包含表单错误消息的 JSON 响应。然后,前端 JavaScript 在收到该响应后,将错误消息显示在模态窗口中。