提问人:DragonFire 提问时间:11/7/2023 最后编辑:CraigDragonFire 更新时间:11/9/2023 访问量:65
对话框未返回 true,因此由于发生事件而未触发 onClick
dialog not returning true, and as consequence not triggering onClick, because of event occurred
问:
这个问题会让我发疯,我正在寻找解决方案;
我在 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 () { 没有关系
对不起,写了很多细节;但请帮我一把,并建议如何克服这个问题。
我做了很多调试和跟踪,我什至尝试通过 .click() 触发事件 *** 硬编码 *** ; 但这也会触发 onClientClick,我最终得到了一个无限循环。
我正在寻找一种方法让内页中的 [ok]/[cancel] 按钮告诉外部 div 关闭并触发 onClick。或者在不触发 onClientEvent 的情况下触发 onClick 事件的方法。
答:
让我尝试解决您最初的问题,而不是解决您使用 iframe 的解决方法的修复程序。
听起来你最初的问题是,当你点击按钮时,它会进行回发,而不是执行你的javascript函数。
发生这种情况的原因是按钮在表单中,并且按钮具有type="submit"
要防止回发并让 javascript 执行处理程序,您需要将按钮设置为onClick
type="button"
我会尽量避免使用iframe来显示模态弹出窗口。
评论
好的,有几件事。
我强烈建议您不要为此打扰或使用 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 个隐藏字段值。
因此,有了上面,结果就是这个弹出对话框,并且可以有回发。
第 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
在上面运行,我们有这个:
当然,问题是内置的确认对话框看起来非常糟糕。
因此,现在让我们使用 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>
现在的结果是这样的:
因此,请注意 jQuery 对话框在第一次运行时如何返回 false(代码不会停止或等待 - 因此我们弹出对话框并返回 false,并且服务器端按钮单击不会运行)。现在,如果用户点击取消,那么我们关闭对话框。如果用户点击 ok(删除),那么我们设置 flag = true,然后再次单击该按钮。这一次,我们的弹出对话框代码再次运行,但现在返回 true。
因此,上面展示了一个聪明的技巧,可以避免使用 JavaScript“promise”并处理异步代码(例如 jQuery.UI 对话框)。
评论