小能豆

Django View 返回具有刷新模式窗口的模板

javascript

我在模态窗口中使用 Django 表单,其中核心内容(在容器中)由 JS 生成。提交 django 模型实例保存时没有任何问题,if form.is_valid() == True模式窗口将关闭,并将焦点切换到当前背景页面。然而,if form.is_valid() == False模式内容只是在单独的 URL 中打开,并占据所有浏览器屏幕,因为视图仅呈现 .html 文件中的一小段代码。

目标是在出现if form_is_valid() == False表单错误时刷新当前条件下的模式窗口。

模板"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">&times;</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>

运行代码片段


阅读 111

收藏
2024-02-28

共1个答案

小能豆

您可以在 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 在收到该响应后,将错误消息显示在模态窗口中。

2024-02-28