I am working on a asp.net (framework 4) that has a requirement for the user to be notified if they are trying to leave the page without saving changes. Well I found a solution by calling the onbeforeunload function via JavaScript. Works great in IE but not in Firefox, Safari or Chrome.
Now here is where the problem comes in. I’m using AJAX postbacks and if the user is prompted to save the changes before leaving the page, any controls inside of the update panel no longer will postback to the server. For example, if a press the save button that is inside of the update panel, nothing happens.
Here are some code snippets
javascript:
window.onbeforeunload = function (e) {
if (doBeforeUnload() == true) {
var ev = e || window.event;
// For IE and Firefox prior to version 4
if (ev) {
ev.returnValue = "You have modified the data entry fields since the last time it was saved. If you leave this page, " +
"any changes will be lost. To save these changes, click Cancel to return to the page, and then Save the data.";
}
// For Safari
return "You have modified the data entry fields since the last time it was saved. If you leave this page, " +
"any changes will be lost. To save these changes, click Cancel to return to the page, and then Save the data.";
}
}
ASP.NET:
<asp:UpdatePanel ID="UpdatePanel1" runat="server" >
<ContentTemplate>
<%--no controls inside of this panel will postback to server if user clicks the “Stay on Page” button--%>
</ContentTemplate>
</asp:UpdatePanel>
Seems to be plenty of posts on the net but no solutions. Any ides besides not using async postbacks?
I came across this question when I was searching for the similar issue. I was able to solve this by doing the following:
var doOnBeforeUnloadCheck = true; // global to set in link button
window.onbeforeunload = function (e) {
if (doOnBeforeUnloadCheck && doBeforeUnload()) {
// do stuff
}
// Make sure to always re-enable check to ensure the event will still trigger
// where not specified to disable event.
doOnBeforeUnloadCheck = true;
}
In a LinkButton you just make sure to set the global to false before running any other javascript or doing the postback:
<asp:LinkButton ID="yourButton" runat="server"
OnClientClick="doOnBeforeUnloadCheck = false;" OnClick="yourButton_Click" />
I came across this solution with help from the following link:
http://www.jimandkatrin.com/CodeBlog/post/LinkButton-UpdatePanel-onbeforeunload.aspx
I found this question before I found my answer so if anyone else has the same issue this might save them some time. Hope that helps.
Related
I am capturing credit card info from a basic USB credit card reader. A bloated stream of ASCII data is sent to the text box, which my js parses down to the useful bits. That all works fine.
I have the following chunk of jquery in my ASP.NET app that works perfectly on a different page, but breaks on the page in question. The only difference between the jquery below, and what I have on the other page that works, is the 1st line, the .unbind(). I added that line because it's the only way I could find to get the "change" listener to fire. But it has a side effect: after the change listener fires and the data stream gets scrubbed, somehow a postback occurs, and then the RAW data stream gets plopped into my text box: txtCreditCardNumber.
IMPORTANT: The card swiper seems to be sending a CRLF at the end of the stream, so maybe this is causing the postback. But that's puzzling because even if I enter something manually into the textbox and hit ENTER, no postback occurs.
The other page doesn't auto-postback when the card is swiped. On this page, without the unbind, the change listener never gets called, but with it, I get correct parsing/scrubbing, followed by the the postback, followed by the textbox being populated with the full raw data stream from the card reader.
$("#txtCreditCardNumber").unbind("keypress");
$('#txtCreditCardNumber').bind('change', function(e) {
e.preventDefault();
if (e.which == 46 || e.which == 8)
return; // always ignore the DELETE and BACKSPACE keys
var element = this;
setTimeout(function() {
var ccRawData = $(element).val();
ccNumber = getCCNumberFromRawData(ccRawData);
ccExpYear = getCCExpYearFromRawData(ccRawData);
ccExpMonth = getCCExpMonthFromRawData(ccRawData, false);
ccNameOnCard = getCCNameOnCardFromRawData(ccRawData);
if (ccExpMonth.length == 1)
ccExpMonth = "0" + ccExpMonth;
$('#txtCreditCardNumber').val(ccNumber);
$('#txtCCExpirationDate').val(ccExpMonth + "" + ccExpYear);
//$('#ccEmbeddedName').html(ccNameOnCard);
$("#txtCreditCardNumber").attr('maxlength', '16');
}, 0);
return false;
});
And here is the ASP.NET textbox:
<asp:TextBox runat="server" ID="txtCreditCardNumber" data-capture="CCAccountNo" CssClass="creditcard" style="width:114px" />
If I could just prevent the postback, I believe the entire problem would be solved. I'm already doing e.preventDefault(), but it has no effect. Any ideas?
I'm trying to add a confirmation dialog to have the user confirm changes to the checked status of an ASPxCheckBox.
Take 1
Based on this DevExpress support center question I'm trying the following code:
<dx:ASPxCheckBox ID="ASPxCheckBox1" runat="server">
<ClientSideEvents CheckedChanged="ConfirmChange" />
</dx:ASPxCheckBox>
With this JavaScript:
function ConfirmChange (s, e) {
console.log(s);
console.log(e);
return false; // For testing
// return confirm(); // Should become this
}
I was hoping/expecting the return false bit to prevent the change, but it happens nonetheless. I've gone through the console logged parameters to see if I can affect anything there, but doesn't look like it. I've also read the CheckedChanged DevExpress documentation but it holds no clue to my purpose either.
Take 2
I've also tried doing this in code behind:
var checkbox = (ASPxCheckBox)myGridView.FindEditRowCellTemplateControl(myCol, "ASPxCheckBox1";
checkbox.Attributes.Add("onclick", "return confirm('You sure?')")
This also pops up the confirm dialog, which fails to prevent a change if cancel is clicked.
Take 3
Finally, based a suggestion in one of the early answers here, I've also tried going the validation route:
<dx:ASPxCheckBox ID="ASPxCheckBox1" runat="server">
<ClientSideEvents Validation="ConfirmChange" />
</dx:ASPxCheckBox>
JavaScript:
function ConfirmChange (s, e) {
e.isValid = confirm();
}
However, this doesn't prevent or revert the change, but presents a validation error if you hit cancel in the confirm dialog.
So, bottom line
How can I inject a client side confirmation dialog before the ASPxCheckBox's change happens?
You cannot prevent the change in ASPxClientCheckBox.CheckedChanged event because this event occurs on the client side when the editor's checked state is changed. You can revert value by using ASPxClientCheckBox.GetChecked method and ASPxClientCheckBox.SetChecked method.
Here is example:
<dx:ASPxCheckBox ID="ASPxCheckBox1" runat="server">
<ClientSideEvents CheckedChanged="ConfirmChange" />
</dx:ASPxCheckBox>
JavaScript:
function ConfirmChange (s, e) {
console.log(s);
console.log(e);
//Save the checked state
value = s.GetChecked();
//Revert changes immediately
s.SetChecked(!s.GetChecked());
result = false; // For testing
// result = confirm(); // Should become this
if (result) {s.SetChecked(value);}
}
I have spent the couple days researching my issue and have not been able to get it to work correctly. I know there are a few topics here that are related to this issue and reading them has helped me but I'm at a bit of a roadblock and would appreciate a push in the right direction.
I wrote a small .NET 3.5 VB.NET web application that allows users to maintain some data. It consists of 3 pages. One requirement I was not completely fond of was that the user wanted to make all of her changes then hit a save button at the end instead of saving back to the DB each time she applied her changes to the grid.
I'm using an session object to store a collection of objects on each page and want to prompt the user with a dialog if they attempt to change the value of a dropdown or leave the page when there are pending actions. After a lot of research here and in other places, I decided to create a hidden field on the page and update its value each time the action collection is updated on the server side. Then I want to evaluate that value and if it's greater than 0, I want to prompt the user to save changes.
My function:
<telerik:RadCodeBlock ID="RadCodeBlock2" runat="server">
<script type="text/javascript">
window.onbeforeunload = confirmExit;
function confirmExit()
{
var actionCount = $get('<%=ActionCounterField.ClientID %>').value;
if (actionCount > 0) {
alert("Pending Changes!");
}
}
</script>
</telerik:RadCodeBlock>
My hidden field declaration:
<asp:HiddenField id="ActionCounterField" runat="server" />
My server side code:
Protected Sub UpdateActionCount()
ActionCounterField.Value = GoalCategoryActionList.Count
End Sub
When I debug the application and add a record to my grid, the server side code is executed correctly. I have also verified that the hidden control is found by the javascript function. What I haven't been able to figure out, though, is why the hidden field value is not found by the function.
Any help is greatly appreciated. Thank you!
OK, I figured out how to do this. I won't claim it's the most elegant solution but it works exactly how I want it to work so I'm happy. Thank you for the responses. I appreciate the help.
First, I changed the hidden field to a telerik RadTextBox and set it up to not display. The RadTextBox just appears to play better with the RadGrid than the hiddenfield was.
<telerik:RadTextBox id="ActionCounterField" runat="server" style="display: none;" AutoPostBack="true" />
Then I wired it up in the AjaxManager to be changed by my RadGrid.
<telerik:RadAjaxManager ID="RadAjaxManager1" runat="server">
<AjaxSettings>
<telerik:AjaxSetting AjaxControlID="RadGrid1">
<UpdatedControls>
<telerik:AjaxUpdatedControl ControlID="ActionCounterField"></telerik:AjaxUpdatedControl>
</UpdatedControls>
</telerik:AjaxSetting>
</AjaxSettings>
</telerik:RadAjaxManager>
I conditionally call the confirmation function. When my user hits the save or undo button, the changes are persisted to the DB or undone without confirmation. If they attempt to leave the page in any other way, however, they are prompted to save their changes. If they hit "OK" the save button handler is called on the server side. If they hit "Cancel", the undo button handler is called.
var allowConfirm = true
window.onbeforeunload = confirmExit;
function confirmExit()
{
var actionCountHolder = document.getElementById("<%=ActionCounterField.ClientID %>");
var actionCount = actionCountHolder.value;
if (allowConfirm == true)
{
if (actionCount > 0)
{
var conf = confirm("You have pending changes. Save them?");
if (conf == true)
{
var saveButton = document.getElementById("<%=btnSave.ClientID %>");
saveButton.click()
}
else
{
var cancelButton = document.getElementById("<%=btnCancel.ClientID %>");
cancelButton.click();
}
}
}
else {
allowConfirm = true;
}
}
Also, I have the save and undo buttons calling the disableConfirm function on their OnClientClick action.
<asp:Button ID="btnSave" OnClick="btnSave_Click" OnClientClick="disableConfirm()" runat="server" Text="Apply" />
<asp:Button ID="btnCancel" OnClick="btnUndo_Click" OnClientClick="disableConfirm()" runat="server" Text="Undo" />
It looks like the Internet Explorer demon has struck again, and I cannot seem to figure this one out:
I have an ImageButton using OnCommand to delete a specific entry from my database. I however have implemented it so that the user will first confirm that they want to delete a specific item.
Here is the code for my ImageButton
<asp:ImageButton runat="server" ID="imgDelete" ImageUrl="~/Controls/TaskDetails/Images/delete.png" OnCommand="Tag_DeleteCommand" Visible='<%# CanDelete %>' OnClientClick="javascript:confirmDialog(this, 'Remove Tag','Are you sure you want to remove this tag?', 1); return false;"
CommandArgument='<%# Eval("TagID") %>' />
And here is my ConfirmDialog function
function confirmDialog(sender, title, message, type) {
//type entities
//1 = warning
//2 = error
//3 = success
//4 = Information
var sender = $(sender);
$("#message_dialog_inner_text").html(message);
$("#message_dialog_message_container").dialog({
modal: true,
title: title,
zIndex: 10003,
dialogClass: (type > 0) ? "message_dialog_type_" + type : "",
position: 'center',
buttons: {
"OK": function () {
//the yes option was selected, we now disable the onclientclick event, and fire the click event.
$(this).dialog("close");
if (sender.hasAttr("href")) {
window.location = sender.attr('href');
} else {
sender.removeAttr("onclick");
sender.trigger("click");
}
},
"Cancel": function () { $(this).dialog("close"); }
}
});
return false;
}
This works fine in Chrome, FF, Safari, but IE is just ignoring it and doing the postback. I have even changed my OnClientClick to "return false;" and it seems to have no impact on the button posting back. I have also changed it from an ImageButton to just a Button, to no avail. I am assuming it has something to do with the OnCommand event, but right I am at a loss! I have implemented this througout a pretty huge application, so I would like to manage the scope of the change. If anyone has some input, it would be greatly appreciated!
EDIT
OK, let me also just stress, I don't want it to post back, and even if I just have OnClientClick="return false;" the command button is still posting back (not what you would expect).
Here is the rendered markup from my ImageButton control
<input type="image" name="ctl00$body$pnlContentRight$pnlCurrentTaskDetails$repTags$ctl00$tagItem$imgDelete" id="ctl00_body_pnlContentRight_pnlCurrentTaskDetails_repTags_ctl00_tagItem_imgDelete" src="Controls/TaskDetails/Images/delete.png" onclick="javascript:confirmDialog(this, 'Remove Tag','Are you sure you want to remove this tag?', 1); return false;" style="border-width:0px;">
This isn't a resolution to your specific issue, but it's a workaround you may want to consider (I've used it in a couple of places):
Make your "delete" button a simple image, not a postback button.
Give it an OnClientClick which calls a local javascript function (passing the relevant data - at a minimum, the ID of the item to be deleted).
That local JS function loads the relevant data into a hidden var (so it can be accessed in your code-behind), and opens the jQuery confirm dialog.
That dialog is configured with NO jquery-dialog buttons. Instead, the launched DIV contains two asp:Buttons: ok and cancel. The cancel button simply closes the jQuery dialog. The OK button is a normal postback button with a server-side OnClick function.
Thus, the page is only posted-back if the user clicks the OK button on the confirm dialog. The confirm-dialog-event function knows which item to delete because that item's ID is in the hidden field.
This is probably not the "right" way to implement this behavior (from an ASP.NET purist standpoint). However, as workarounds go, I don't think it's too painfully kuldgey. And in my experience, it seems to work across all browsers (assuming they have JS enabled, of course). HTH.
You're OnClientClick is always returning false, which means that the event will never be executed. Try returning the input from the confirm like this:
OnClientClick="return confirmDialog(...);"
You will need to make sure that there is a way to return true from the confirmDialog function too. It looks like that function always returns false too.
I'm not very familiar with the jQuery UI dialog, but in concept it should work like this:
buttons: {
"OK": function () { return true; }, //perform a postback and execute command
"Cancel": function () { return false; } //abort postback and do nothing
}
I have what I thought was a pretty straightforward javascript issue, but I'm starting to go nuts trying to figure out my problem.
I have a slow page, and it was possible for users to click submit, then click another button while waiting on the page to load, it was creating issues. I thought I could display a please wait message and disable the submit button on click. Below is the function, I am using asp.net 3.5 so there's a name mangling issue, because of this I was using a getElemenetsByName and scanning for the right items (not awesome but it seems to work). When I run this, the button becomes disabled, but then the page just sits there, the server never gets called. I tried in firefox and I didn't see any errors in firebug, but when I set a breakpointon the server, the server def does not get called. I tried returning true in case there was an output expected, but nada. When I commend out the content of processing(){ // stuff } then it works fine, so something in there seems to be killing me.
function processing() {
var pleaseWaitID = "lblPleaseWait";
var submitBtnName = "btnSubmit";
var submitControl = document.getElementsByTagName('input');
var pleaseWaitlbls = document.getElementsByName(pleaseWaitID);
for (pleaseWait in pleaseWaitlbls) {
if (pleaseWaitlbls[pleaseWait].style != null) {
pleaseWaitlbls[pleaseWait].style.visibility="visible";
}
}
for (submitButton in submitControl) {
if (submitControl[submitButton].name != null) {
if (submitControl[submitButton].name.search(submitBtnName) != -1) {
submitControl[submitButton].disabled = "disabled";
}
}
}
return true;
}
.....
asp:Button ID="btnSubmit" name="btnSubmit" SkinID="MainAction" runat="server" Text="Submit" OnClientClick = "javascript:processing();"
OnClick="btnSubmit_Click" meta:resourcekey="btnSubmitResource1"
Any ideas on what I've screwed up here?
Thanks you for your time.
Asp.net Custom user control button. How to stop multiple clicks by user
I had the same type of problem this may or may not help.