1

TL;DR: 如果在没有选择 ListBox 的情况下单击 Edit 按钮,触发验证失败,为什么Delete需要在浏览器响应之前单击两次链接?

使用下面的源代码作为一个非常简单的菜单,我有三个链接:

  1. New- 不执行验证并重定向到“创建”表单
  2. Edit- 检查是否选择了 ListItem,如果是,则重定向到“编辑”表单,并使用作为参数提供的 ID 值
  3. Delete- 重定向到“删除”页面,无论是否做出选择

我注意到一个奇怪的行为,并在这个简单的单页解决方案中重现(从 OneDrive 下载链接):

  1. 加载页面
  2. 单击Edit而不从 ListBox 中进行选择(出现验证错误)
  3. 点击Delete- 没有任何反应 - 为什么?
  4. 点击Delete- 服务器端重定向成功发生,但这应该发生在上面的第 3 步

以下是我的浏览器中发生的情况(在 Chrome、FF 和 Edge 中测试) - 请注意,需要在删除链接上单击两次: 在此处输入图像描述

更新

问题似乎在 ASP.Net 的表单提交代码中:

function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

    // On first click - this logic path is never reach, but on the second click, it is reached

        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}

在我if手动调用Page_ClientValidate().

代码

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test Page</title>
    <script>
        function RedirectToPageWithSelectedId() {
            if (Page_ClientValidate("mustSelect")) { // Asp.Net client-side validation, passing ValidationGroup as parameter
                var li = $("#<%=ListBox1.ClientID%> option:selected");
                var i = li.val();
                if (parseInt(i) != NaN) {
                    window.location.href = "/edit/" + i;
                }
            }
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <p>
                <asp:ListBox ID="ListBox1" runat="server" />
                <asp:RequiredFieldValidator ID="Rfv1" runat="server" Text="Selection required" ValidationGroup="mustSelect" ControlToValidate="ListBox1" Display="Dynamic" />
            </p>
            <ul>
                <li>
                    <asp:HyperLink ID="lnk_new" runat="server" Text="New" NavigateUrl="~/new" />
                </li>
                <li>
                    <asp:HyperLink ID="lnk_edit" runat="server" Text="Edit Selected" onclick="RedirectToPageWithSelectedId(); return false;" href="#" />
                </li>
                <li>
                    <asp:LinkButton ID="lnk_delete" runat="server" Text="Delete" />
                </li>
            </ul>
        </div>
    </form>
</body>
</html>

如果需要,我可以更新以提供页面的代码隐藏;问一下。

4

2 回答 2

2

在使用 Chrome 的调试器进行大量调查后,我发现了以下逻辑和解决方法。如果我弄错了,或者是否有更好的方法在客户端与 ASP.Net 的验证控件进行交互,请告诉我?

当单击 LinkBut​​ton 时,ASP.Net 会通过它的验证逻辑工作,即使该控件没有引起验证。这是让我吃惊的第一件事。在处理了验证逻辑之前,不会实际提交表单。

ASP.Net webforms 客户端验证

在验证期间,设置了两个页面级变量:

Page_IsValid

这是一个整体布尔值,指示所有验证器都是有效的。

Page_BlockSubmit

这通常持有相反的值Page_IsValid,并阻止表单提交 if true

代码中的问题

当我的Edit链接被点击时,我的代码触发了特定验证组的客户端验证:

Page_ClientValidate("mustSelect");

在那个方法中,Page_IsValid变成false,因此Page_BlockSubmit变成true。这可以防止表单在显示验证错误后执行任何操作,这是预期的。

LinkBut​​ton 的单击事件会出现问题。按下时,无论该 LinkBut​​ton 是否正在执行验证,都会执行以下 JavaScript:

function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

        // This is never reached if Page_BlockSubmit = true

        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}

更重要的是之前的验证结果仍然保存在浏览器中,所以Page_BlockSubmit仍然是true. 这会导致上述方法跳过提交表单的内部代码,这意味着表单永远不会被提交。

奇怪的是,方法完成后,两者都Page_IsValidPage_BlockSubmit重置为默认值。这就是页面在第二次编辑点击时提交的原因。

解决方法(或肮脏的黑客?)

这感觉就像一个完整的 hack,但是通过在Page_BlockSubmit单击 LinkBut​​ton 时强制值为 false,一切都按预期工作,并且无需手动开始重置validation.isvalid属性或隐藏消息。所有其他验证组/逻辑继续正常工作,但编辑链接现在按用户预期工作:

<asp:LinkButton ID="lnk_delete" runat="server" Text="Delete" OnClientClick="Page_BlockSubmit = false;" />

同样,我不知道这是否会破坏 ASP.Net 的任何工作原理,并且希望能提供任何意见。

于 2018-02-01T13:19:18.497 回答
1

我会做这样的事情。给<div>包含元素一个类名并按类绑定点击lnk_edit。现在,您无需使用 就可以查找是否选择了元素ClientID。这也适用于myContainer您想要的任意数量的副本,而无需添加更多的 jQuery 代码。

<div class="myContainer">
    <p>
        <asp:ListBox ID="ListBox1" runat="server" />
    </p>
    <ul>
        <li>
            <asp:HyperLink ID="lnk_new" runat="server" Text="New" NavigateUrl="~/new" />
        </li>
        <li>
            <asp:HyperLink ID="lnk_edit" runat="server" Text="Edit Selected" href="#" CssClass="myEditLink" />
            <span class="myEditLinkWarning"></span>
        </li>
        <li>
            <asp:LinkButton ID="lnk_delete" runat="server" Text="Delete" />
        </li>
    </ul>
</div>

<script type="text/javascript">
    $('.myContainer .myEditLink').click(function () {
        $(this).closest('div').find('select option').each(function () {
            if ($(this).prop('selected')) {
                window.location.href = "/edit/" + $(this).val();
            }
        });
        $(this).closest('div').find('.myEditLinkWarning').html('Please select');
    });
</script>
于 2018-01-31T15:57:17.330 回答