对话框未返回 true,因此由于发生事件而未触发 onClick

dialog not returning true, and as consequence not triggering onClick, because of event occurred

提问人:DragonFire 提问时间:11/7/2023 最后编辑:CraigDragonFire 更新时间:11/9/2023 访问量:65

问:

这个问题会让我发疯,我正在寻找解决方案;

我在 asp.net 页面中做了一个隐藏的 div,以及一个 JavaScript 函数,用于在单击 asp.net 按钮时将其显示为对话框,此 JavaScript 函数由 onClintClick 触发;一切都很好。

我在该 div 中添加了一些 asp.net 控件,这里出现了一些问题。单击控件后,整个页面都会进行回发,并且 div 会隐藏,这不会与用户进行交互式会话。

在这一点上,我找到了一个解决方案,它更有用,使对话可重用。我在 div 中添加了一个 iframe,并使其显示一个外部页面。这样,当用户在 iframe 中与页面交互时,对话框(在本例中为弹出 div)将不会进行回发。目前为止,一切都好。

现在,我需要一种内部页面与 div 对话的方式(在本例中,div 是父级)来关闭它,返回值为 true 或 false(请记住 div 是对话,返回值为 true 或 false)。幸运的是,我找到了一种方法来关闭 div,但它看起来的问题结束了父级的“线程”。因此,看起来等待 true/false 值的 div 也不会得到。

在图片 01.jpg 中:单击 [delete] 时,会触发 onClientClick 函数以显示包含 iFrame 的圆角 div 以显示另一个页面:

function MyConfirm2(btn, lcWidth, lcHeight, lcTitle, DivID, frm) {
    result = false;
    myDialog = $(DivID);
    document.getElementById('iframepage').src = frm;

    myDialog.dialog({
        title: lcTitle,
        modal: true,
        // appendTo: 'form',
        classes: { "ui-dialog": "lcDialog" },
        width: lcWidth + 20,
        height: lcHeight - 20,
        open: function () {
            $("#myDialogOverlay").show();
        },
        close: function () {
            //debugger;
            $("#myDialogOverlay").hide();
            document.getElementById('iframepage').src = '';
        }
    })
    return result;
}

现在,用户应该从内页单击“确定”或“取消”,这应该与外部 div 对话并通知它关闭。下面是触发的用于执行关闭的 javaScript 函数:

var receiveMessage = function (event) {
    if (event.data == "close-iframe") {
        myDialog.returnValue = true;
        myDialog.dialog("close");
        return;
    } else {
        myDialog.returnValue = false;
        result = false;
        myDialog.dialog("close");
    }
}
window.addEventListener("message", receiveMessage, false);

这里的问题是,尽管关闭完美地执行了它的任务,并且返回值为 true,但它切断了父页面的线程,因此它没有按应有的方式响应;对话越来越近了;但关闭不会触发 OnClick 事件,该事件应在分配 'true' 并调用 myDialog.dialog(“close”) 后触发;

在调试代码时,我发现它返回到函数(事件)并在行 myDialog.dialog(“close”) 之后继续执行代码;因为它与打开/关闭代码中的 close: function () { 没有关系

对不起,写了很多细节;但请帮我一把,并建议如何克服这个问题。

enter image description here

我做了很多调试和跟踪,我什至尝试通过 .click() 触发事件 *** 硬编码 *** ; 但这也会触发 onClientClick,我最终得到了一个无限循环。

我正在寻找一种方法让内页中的 [ok]/[cancel] 按钮告诉外部 div 关闭并触发 onClick。或者在不触发 onClientEvent 的情况下触发 onClick 事件的方法。

JavaScript asp.net vb.net 对话框

评论


答:

2赞 nsquires 11/7/2023 #1

让我尝试解决您最初的问题,而不是解决您使用 iframe 的解决方法的修复程序。

听起来你最初的问题是,当你点击按钮时,它会进行回发,而不是执行你的javascript函数。

发生这种情况的原因是按钮在表单中,并且按钮具有type="submit"

要防止回发并让 javascript 执行处理程序,您需要将按钮设置为onClicktype="button"

我会尽量避免使用iframe来显示模态弹出窗口。

评论

0赞 DragonFire 11/7/2023
我正在使用 asp.net 按钮控制...不是普通的 HTML 控件。在 iframe 中,我需要 onClick 事件和 onClientClick 事件
0赞 nsquires 11/7/2023
asp.net 按钮控件仍呈现为普通的 html 按钮。您可以将其配置为任何类型的按钮。
0赞 DragonFire 11/8/2023
我需要的不仅仅是按钮。我需要日历、下拉列表、复选框等来回发并导致对话框崩溃。Iframe 是一个很好的解决方案
0赞 Albert D. Kallal 11/8/2023
您可以采用 ajax 和 web 方法,也可以采用更新面板。请参阅下面的答案,该答案显示了如何允许 jQuery.UI 对话框接受/享受/拥有/使用回发,但不折叠。因此,正确使用更新面板可以解决此问题。
0赞 Albert D. Kallal 11/8/2023
第二个问题是如何将真/假返回到对话框的按钮单击。这里的诀窍概述如下:stackoverflow.com/questions/75520459/......
2赞 Albert D. Kallal 11/8/2023 #2

好的,有几件事。

我强烈建议您不要为此打扰或使用 iFrame。

(原因当然是你不能真正让iFrame与你放置iFrame的页面“对话”。

因此,下一个问题当然是,任何具有回发的对话框(您使用的是 jQuery.UI 对话框)通常都会导致对话框崩溃。

这些问题有 2 种常规解决方案。

首先,采用网络方法。当然,这种所谓的按钮和代码的“ajax”在今天经常风靡一时,因为这里的目标是没有回发,并在客户端浏览器中推送/拥有/运行尽可能多的代码。这个伟大目标的原因当然是没有回发(页面往返),那么生成的 Web 应用程序将非常快速地响应,并且实际上响应与桌面应用程序一样好。当你用这个设计概念走得超级远时,你甚至可以在浏览器中运行电子表格或文字处理器。

因此,今天的许多框架都在“尝试”和“想要”将尽可能多的代码移动到客户端。您可以通过调用/使用 Web 方法避免回发。

但是,您可以在 Web 表单中采用一种秘密武器,而该秘密武器当然是采用更新面板。

如果将 jQuery.UI 对话框的弹出 div 放在更新面板内,则会发现弹出对话框可以承受并承受回发。

因此,这种方法几乎可以解决几乎所有问题。

所以,假设我想要一个开始日期提示和一个结束日期提示。假设我使用了日历控件。好吧,当您使用日历控件时,在选择日期时,会发生回发。但是,我们想要一个开始日期和一个结束日期,我们希望在弹出对话框中使用它。

所以,我们有这个标记:

<div id="startend" runat="server" style="display: none">
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:HiddenField ID="hStart" runat="server" ClientIDMode="Static" />
        <asp:HiddenField ID="hEnd" runat="server" ClientIDMode="Static" />
        <div style="float: left">
            <h4>Select Start Date</h4>

            <asp:Calendar ID="dtStart" runat="server" Height="200px" Width="300px"
                BorderColor="Black"
                BorderStyle="Solid" BorderWidth="2px">
                <DayHeaderStyle Height="40px" />
                <DayStyle BorderStyle="Solid"
                    BorderColor="Black"
                    BorderWidth="1"
                    HorizontalAlign="Right"
                    VerticalAlign="Top" Height="40px" />
                <OtherMonthDayStyle BackColor="LightSteelBlue" />
                <SelectorStyle CssClass="btn-info" />

                <TitleStyle Height="40px" />

                <TodayDayStyle BackColor="LightSkyBlue" />
                <WeekendDayStyle BackColor="Ivory" Height="30px" />
            </asp:Calendar>
        </div>


        <div style="float: left; margin-left: 30px">
            <h4>Select End Date</h4>

            <asp:Calendar ID="dtEnd" runat="server" Height="200px" Width="300px"
                BorderColor="Black"
                BorderStyle="Solid" BorderWidth="2px">
                <DayHeaderStyle Height="40px" />
                <DayStyle BorderStyle="Solid"
                    BorderColor="Black"
                    BorderWidth="1"
                    HorizontalAlign="Right"
                    VerticalAlign="Top" Height="40px" />
                <OtherMonthDayStyle BackColor="LightSteelBlue" />
                <SelectorStyle CssClass="btn-info" />

                <TitleStyle Height="40px" />

                <TodayDayStyle BackColor="LightSkyBlue" />
                <WeekendDayStyle BackColor="Ivory" Height="30px" />
            </asp:Calendar>
        </div>

    </ContentTemplate>
   </asp:UpdatePanel>
 </div>

所以,请记住,设计模式是这样的:

 start of your div to pop

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
     <ContentTemplate>

       -- everything in here - including the calendar control


      </ContentTemplate>
  </asp:UpdatePanel>

</div>   --- end of our div

因此,我们弹出的 div 在“内部”具有更新面板。

在上面之后,我们有我们的jQuery.UI对话框代码。

<script>

    function popdate() {
        console.log("start")
        var myDialog = $("#startend");
        myDialog.dialog({
            title: "Select booking dates",
            modal: true,
            width: "720px",
            resizable: true,
            autoOpen: false,
            appendTo: "form",
            dialogClass: "dialogWithDropShadow",
            buttons: {
                ok: function () {
                    myDialog.dialog('close');
                    $('#txtStartDate').val($('#hStart').val())
                    $('#txtEndDate').val($('#hEnd').val())
                },
                Cancel: function () {
                myDialog.dialog('close');
                }
            }
        });

        myDialog.dialog('open');

    }

</script>

日历的回传(代码隐藏)是这样的:

Protected Sub dtStart_SelectionChanged(sender As Object, e As EventArgs) Handles dtStart.SelectionChanged

    hStart.Value = dtStart.SelectedDate

End Sub

Protected Sub dtEnd_SelectionChanged(sender As Object, e As EventArgs) Handles dtEnd.SelectionChanged

    hEnd.Value = dtEnd.SelectedDate

End Sub

请记住,由于这是一个更新面板,因此只有面板内部的控件可以通过代码隐藏来更改。因此,我们删除了 2 个隐藏字段,这将允许其他代码获取/获取/使用/享受 2 个选定的值。在对话框关闭时,我还有一些 JavaScript 代码可以将所选日期的 2 个值复制到标准文本框 - 这仅用于演示目的,但它为您提供了多种方法和多个选项,用于将所选日期与客户端代码一起使用,或者您可以使用服务器端代码并使用 2 个隐藏字段值。

因此,有了上面,结果就是这个弹出对话框,并且可以有回发。

enter image description here

第 2 部分 -- 如何返回 true/false

当然,这个问题的第二部分是,我们在使用 asp.net Web 表单时,当然都会使用“非常”有用的技巧,即将按钮拖放到表单上,同时具有客户端单击事件,然后是服务器端事件。

如果客户端事件返回 true,则服务器端代码将运行。如果客户端事件返回 false,那么服务器端按钮代码当然不会运行。

一个典型的用例是确认一些删除或危险的选项。

然而,上述问题在于jQuery.UI对话框,实际上几乎所有的JavaScript库代码都是非阻塞的!!

这意味着当您弹出(调用/使用)jQuery.UI对话框时,代码不会停止,也不会等待!

从设计上讲,所有这些代码都是非阻塞的,这意味着您不能停止代码以等待用户在对话框中的选择。这适用于浏览器的内置确认,因为该确认对话框确实会停止并且不是异步代码。

因此,假设我们有这个按钮来删除记录,我们通过使用客户端 JavaScript 例程返回 true 或 false来“确认”删除。

因此,说一个带有删除按钮的网格视图。

所以,说这个标记:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    CssClass="table table-hover" Width="50%"
    DataKeyNames="ID" >
    <Columns>
        <asp:BoundField DataField="FirstName" HeaderText="First Name"   />
        <asp:BoundField DataField="LastName" HeaderText="First Name"    />
        <asp:BoundField DataField="City" HeaderText="City"    />
        <asp:BoundField DataField="HotelName" HeaderText="Hotel Name"   />
        <asp:BoundField DataField="Description" HeaderText="Descripiton" />
        <asp:TemplateField HeaderText="Edit" ItemStyle-HorizontalAlign="Center"
            ItemStyle-Width="140px"
            >
            <ItemTemplate>
                <asp:ImageButton ID="cmdDelete" runat="server"
                    ImageUrl="~/Content/trashcan1.png"
                    Width="48px"
                    Height="40px"
                    onclick="cmdDelete_Click"
                    OnClientClick="return mydelpop(this)"
                    />

                <asp:ImageButton ID="cmdEdit" runat="server"
                    ImageUrl="~/Content/edit2.png"
                    Width="48px"
                    Height="40px"
                    onclick="cmdEdit_Click"
                    style="margin-left:15px"
                    />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

请注意,关闭删除按钮如何同时具有客户端单击事件和服务器端事件。

因此,函数 mydelpop() 可以返回 true 或 false。

此 JavaScript 代码:

<script>

   function mydelpop(btn) {
       return confirm("Really delete this Hotel?")
   }
</script>

因此,加载网格的代码是这样的:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadGrid()
    End If

End Sub

Sub LoadGrid()
    GridView1.DataSource =
        MyRst("SELECT * FROM tblHotelsA ORDER BY HotelName")
    GridView1.DataBind()
End Sub

还有我们的删除按钮代码(图像按钮,但它可以是按钮、链接按钮或在本例中为图像按钮)。

Protected Sub cmdDelete_Click(sender As Object, e As ImageClickEventArgs)

    Dim btn As ImageButton = sender
    Dim gRow As GridViewRow = btn.NamingContainer

    Dim intPK As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
    Dim cmdSQL As New SqlCommand("DELETE FROM tblhotelsA WHERE ID = @ID")
    cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = intPK
    MyRstPE(cmdSQL)
    LoadGrid()    ' re-load grid update display

End Sub

在上面运行,我们有这个:

enter image description here

当然,问题是内置的确认对话框看起来非常糟糕。

因此,现在让我们使用 jQuery.UI 对话框。

但是,如上所述,jQuery.UI对话框是“异步”的,代码不会等待。所以,我们必须把代码骗出来一点,因为当我们第一次启动对话框时,它会运行,显示对话框,然后返回 false(所以服务器端删除代码不会运行)。

但是,然后我们从对话框中选择一个值(是删除),然后我们设置一个标志,然后再次单击该按钮(我们再次单击该按钮,其中包含用户的 Javascript 代码),函数返回 true,服务器端代码现在运行。

jQuery.UI对话框的优点是我们可以将删除对话框定位在正确/当前行单击上。

所以,现在我们的 JavaScript 看起来像这样:

<script>

    var mydelok = false
    function mydelpop(btn) {

        if (mydelok) {
            mypopok = false
            return true
        }
        myDialog = $("#mypoparea")
        myDialog.dialog({
            title: "Delete Hotel",
            modal: true,
            sizable: true,
            width: '380',
            closeText: "",
            position: { my: 'right top', at: 'left bottom', of: btn },
            dialogClass: "dialogWithDropShadow",
            buttons: {
                Delete: function () {
                    myDialog.dialog('close')
                    mydelok = true
                    btn.click()
                },
                cancel: function () {
                    myDialog.dialog('close')
                }
            }
        })
        return false
    }
</script>

我们的 pop div 区域是这样的:

            <div id="mypoparea" style="display:none">
                <h4>Delete this Hotel?</h4>
                <h4><i>(this can't be un-done)</i></h4>
            </div>

现在的结果是这样的:

enter image description here

因此,请注意 jQuery 对话框在第一次运行时如何返回 false(代码不会停止或等待 - 因此我们弹出对话框并返回 false,并且服务器端按钮单击不会运行)。现在,如果用户点击取消,那么我们关闭对话框。如果用户点击 ok(删除),那么我们设置 flag = true,然后再次单击该按钮。这一次,我们的弹出对话框代码再次运行,但现在返回 true。

因此,上面展示了一个聪明的技巧,可以避免使用 JavaScript“promise”并处理异步代码(例如 jQuery.UI 对话框)。