So I am trying to change the confirm boxes in my application to something a bit more stylish.
The jquery-confirm.js add on was very appealing but I am really struggling to get it to work the way I want.
I have a simple link button on the page.
<asp:LinkButton ID="lnkDelete" CssClass="btn btn-danger" runat="server" OnClientClick="return ShowConfirm();" CommandArgument='<%#Eval("StatusId")%>' OnClick="DeleteStatus">
On their site this is the recommended implementation, but it doesn't return a value or stop postback.
$.confirm({
title: 'Encountered an error!',
content: 'Something went downhill, this may be serious',
type: 'red',
typeAnimated: true,
buttons: {
tryAgain: {
text: 'Try again',
btnClass: 'btn-red',
action: function(){
}
},
close: function () {
}
}
});
I understand that I can move my onclick function into this, however it then will not be reusable. I just want to stop postback when the user hits cancel. That way I can call it from anywhere and it will just work.
I tried a few things to no avail here are a few examples.
None of these stop the postback, but thought I should include what I have tried.
function ShowConfirm() {
var Confirmed = $.confirm({
title: 'Please Confirm!',
content: 'Are you sue that you want to delete this record?',
type: 'red',
typeAnimated: true,
buttons: {
tryAgain: {
text: 'Delete',
btnClass: 'btn-red',
action: function () {
this.preventDefault();
}
},
close: function () {
}
}
});
return Confirmed;
}
Another one
function confirmation() {
var defer = $.Deferred();
$.confirm({
title: 'Please Confirm!',
content: 'Are you sue that you want to delete this record?',
type: 'red',
typeAnimated: true,
buttons: {
tryAgain: {
text: 'Delete',
btnClass: 'btn-red',
action: function () {
//Do something
defer.resolve(true);
}
},
close: function () {
//Do Something
defer.resolve(false);
}
}
});
return defer.promise();
};
function ShowConfirm() {
confirmation().then(function (answer) {
console.log(answer);
ansbool = (String(answer) == "true");
if (ansbool) {
alert("this is obviously " + ansbool);//TRUE
} else {
alert("and then there is " + ansbool);//FALSE
}
});
}
I also tried the last one with sending a return value, but that doesn't work either.
My onclick server side code always executes.
Any Help would be greatly appreciated.
Ok, so the way this works?
In near "every" case, using some jQuery.UI dialog, sweetalert and in 99% of cases?
These jQuery and JavaScript add-ins ALL, and in ALL cases have one huge "similar" aspect:
that is the code does not wait, nor block the calling code.
The technical term for this type of code is what we call asynchronous.
In a nut shell, WHEN you call such code, the prompt dialog or whatever WILL display, but the code does NOT halt. The routine you call will 100% RUN though its code, display the dialog or whatever and THEN 100% finish, exit and return the value.
The reason for such code is to NOT freeze up the browser, not damage the re-plot, and display of information.
As a result, about the only two commands in JavaScript that actually halt code is
"alert()", and confirm().
The above two commands will halt code. Thus, your question:
You have a plane jane button, and say some code to delete or perform a damaging option, then we all wired up code like this:
<asp:Button ID="cmdDelete" runat="server" Text="Server delete prompt"
OnClientClick="return confirm('Really delete this file?');" />
And, as we know, if user hits cancel, then the button code does not run.
However, what about those js add-ins, and fancy dialogs? Well, they do NOT wait.
I don't have your particular js add-in, but since we all use jQuery, then I give an example how to do this with jQuery.UI.
So, we take the above button, and now do this:
<asp:Button ID="cmdTest" runat="server" Text="Server Delete Prompt"
ClientIDMode="Static"
OnClientClick="return mydeleteprompt(this)"/>
Now, in above, we call a routine, and it will "display" our dialog prompt. But remember that rule above: The code FLOWS though, does not halt the calling js code.
So, what we need to do is STILL RETURN false the first time. (and now our cool prompt dialog is displayed.
the way to make this work? Well, in above we pass "this". In this context, "this" is the current button. So, our code now looks like this:
<div id="MyDialog" style="display:none">
<h4><i>my cool dialog text</i></h4>
<h4><i>This delete can't be undone</i></h4>
</div>
</div>
<script>
var mydeleteok = false
function mydeleteprompt(cmdBtn) {
if (mydeleteok) {
return true
}
myDialog = $("#MyDialog")
myDialog.dialog({
title: "Delete the whole server system",
modal: true,
appendTo: "form",
buttons: {
ok: function () {
myDialog.dialog('close')
mydeleteok= true
$(cmdBtn).click()
},
cancel: function () {
myDialog.dialog('close')
}
}
})
return false
}
Note VERY - but super duper close in above. The routine will return false. That means you click on the button, call the js routine, dialog is displayed, AND THEN FALSE is returned.
Now, the dialog is displayed. If you hit ok button, we set our variable = true AND THEN click the button again!!!!
This time, the same routine will run, but we set our "flag" = true, and the code runs, and returns true, and our server side button code will run.
It will look like this:
So, user click on button, code runs, display dialog, returns "false".
Now, if the user hits "ok", then we run this code:
buttons: {
ok: function () {
myDialog.dialog('close')
mydeleteok= true
$(cmdBtn).click()
},
So, what happens is we set our flag = true, and then click the button again!!! This time, the button calls our routine, but this time the routine WILL return true, and now our server side code for that button will run.
So, your HUGE issue and problem? Near 100%, if not all JavaScript code these days runs asynchronously. It does NOT WAIT.
So, there are advanced concepts such as "await" and things like JavaScript "promise", but it still DOES NOT solve this issue.
So, the asp.net button click event, and using onclientclick is a great feature, but it tends to break down a bit when you want to use some type of dialog "add-in", since as I stated, NONE of them wait. So, you have to adopt the above concept, set a flag (that flag code ONLY runs on page load - first time.
In fact, one could make the case that after I use the .click() to run that button, I probably should set that flag = false again. However, since that server side button is causing a post-back, then in most cases, our flag will be re-set to false.
Edit: Example with jquery-confirm.
As noted, I never used that confirm library (there is about 1+ million of them to be found - you should perhaps have provide a link).
Regardless, that dialog works like this:
<asp:Button ID="Button1" runat="server" Text="Button" CssClass="btn"
OnClick="Button1_Click"
OnClientClick="return myconfirm(this)"
/>
<script>
var myconfirmok = false
function myconfirm(btn) {
if (myconfirmok) {
return true
}
$.confirm({
title: 'Confirm!',
content: 'Simple confirm!',
buttons: {
confirm: function () {
myconfirmok = true
$(btn).click()
},
cancel: function () {
console.log("user hit cancel")
}
}
});
return false // routine MUST return false!!!!
}
NOTE very careful in above - we return false on the last line!!!
So, button is clicked , client side code runs, displays dialog, returns false.
Now, user either hits cancel button, or hits confirm. If they hit confirm, we set our flag = true, and then click the button passed again. Now, our routine runs again, and returns true this time, and thus your server side code now runs.
Edit3: - the issue is use of LinkButton
The issue here is that to use jQuery (or even JavaScript) to CLICK a link button?
You have to use this:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Eval("HotelName") %>' >
</asp:TextBox>
<asp:LinkButton ID="cmdDel" runat="server" ClientIDMode="Static"
CommandArgument='<%# Eval("ID") %>'
onclick="cmdDel_Click"
OnClientClick="return myconfirm(this)"
>delete</asp:LinkButton>
<br />
</ItemTemplate>
</asp:Repeater>
<script>
var myconfirmok = false
function myconfirm(btn) {
if (myconfirmok) {
return true
}
$.confirm({
title: 'Confirm!',
content: 'Simple confirm!',
buttons: {
confirm: function () {
myconfirmok = true
$(btn)[0].click()
},
cancel: function () {
console.log("user hit cancel")
}
}
});
return false // routine MUST return false!!!!
}
</script>
So, you have to address the click even with [0].
Of course, I never use a link button - I useally just drop in a standard button, and there not a whole lot of reason to use a Linkbutton. But, the issue was and is use of jQuery.Click - it needs that [0] for the click event to work.
The code behind for my linkbutton click event is this:
Protected Sub cmdDel_Click(sender As Object, e As EventArgs)
Dim cmdDel As LinkButton = sender
Dim intPKID As Integer = cmdDel.CommandArgument
Debug.Print("code here to delete row with PK id = " & intPKID)
' get current repeater row
Dim OnerepRow As RepeaterItem = cmdDel.NamingContainer
Debug.Print("Repeter index row click = " & OnerepRow.ItemIndex)
' get hotel name texgt box
Dim txtHotel As TextBox = OnerepRow.FindControl("TextBox1")
Debug.Print(txtHotel.Text)
End Sub
And when I run it
WebForms keeps re-rendering a TextBox control with a data- attribute in spite of my code removing it on PostBack-- which I shouldn't have to do in the first place, since the PostBack process clears attributes. I've tried clearing the attributes in OnInit and OnUnload, but they somehow reappear after leaving code-behind. They only ever reset through the TextChanged event.
I'm going crazy trying to figure out if I have a cache setting somewhere in my web.config that would prevent ASP.NET from properly removing this attribute.
For reference, the (as far as I can determine) relevant sections of my code:
.aspx JavaScript:
$("[data-confirm]").each(function () {
var alertText = $(this).attr("<%= _data_confirm %>");
$(alertText).dialog({
modal: true,
draggable: false,
resizable: false,
closeOnEscape: false,
title: "Note",
width: 330,
buttons: {
"Continue with Application": function () {
$(this).dialog("close");
}
}
});
});
.aspx.cs C#:
protected override void OnInit(EventArgs e)
{
if (Page.IsPostBack)
{
ClearIraDistributionConfirmation();
}
iraDistribution.TextChanged += iraDistribution_TextChanged;
}
void iraDistribution_TextChanged(object sender, EventArgs e)
{
if (SessionFormData.ConfirmedIraDistribution == false
&& SessionFormData.IraDistribution.HasValue
&& SessionFormData.IraDistribution.Value > 0)
{
iraDistribution.Attributes[_data_confirm] =
"<div>You must submit a copy of the first page of your 2014 federal tax return to verify the rollover amount.</div>";
iraDistribution.Attributes[_aria_live] = "assertive";
SessionFormData.ConfirmedIraDistribution = true;
}
else if (SessionFormData.ConfirmedIraDistribution)
{
ClearIraDistributionConfirmation();
}
}
private void ClearIraDistributionConfirmation()
{
if (SessionFormData.ConfirmedIraDistribution)
{
iraDistribution.Attributes.Clear();
}
}
I've verified that at the end of the PostBack cycle, iraDistribution has no attributes set. As soon as my .aspx JS hits the very first line of JavaScript -- which is way before the JS I pasted here -- iraDistribution has its data-confirm attribute set.
What am I missing?
The answer to this question is: The Page Life Cycle.
I made the mistake of trying to check for TextBox values in OnInit when they weren't yet available. OnUnload didn't work either because the values had already been rendered to output at that point.
I've fixed this bug by reordering the code above and moving it into the OnLoadComplete event. My code now looks like (well -- not quite like this, but it's abbreviated to remove code that interacts with the Session, functions I defined to improve readability, etc.):
protected override void OnLoadComplete(EventArgs e)
{
base.OnLoadComplete(e);
if (SessionFormData.ConfirmedIraDistribution)
{
iraDistribution.Attributes.Clear();
}
else if (SessionFormData.ConfirmedIraDistribution == false
&& SessionFormData.IraDistribution.HasValue
&& SessionFormData.IraDistribution.Value > 0)
{
iraDistribution.Attributes[_data_confirm] =
"<div>You must submit a copy of the first page of your 2014 federal tax return to verify the rollover amount.</div>";
iraDistribution.Attributes[_aria_live] = "assertive";
SessionFormData.ConfirmedIraDistribution = true;
}
}
The moral of this story: The Page Life Cycle will eat your lunch.
I have a LinkButton that executes on the server and changes the page. Historically, I've had a confirm message box that executes OnClientClick to ensure the user would like to navigate away.
So far it looks like this:
ASP.NET:
<asp:LinkButton runat="server" ID="ChangePage" Text="Change page"
OnClientClick="confirm('are you sure you want to change page?');"
OnClick="Navigate" >
Change Page
</asp:LinkButton>
HTML Output:
<a id="MainContent_ChangePage"
onclick="confirm('are you sure you want to change page?');"
href="javascript:__doPostBack('ctl00$MainContent$ChangePage','')" >
Change page
</a>
This all works fine like this. The trouble is that I'm trying to replace all confirm boxes with a prettier jQuery-UI implementation like this:
window.confirm = function (message, obj) {
$('<div/>')
.attr({ title: 'Webpage Confirm'})
.html(message)
.dialog({
resizable: false,
modal: true,
width: 500,
buttons: {
"OK": function () {
__doPostBack(obj, '');
$(this).dialog('close');
return true;
},
"Cancel": function () {
$(this).dialog('close');
return false;
}
}
});
};
I believe this has to do with the fact that the confirm dialog operates synchronously, while jQuery dialogs occur asynchronously. However, I thought setting modal: true would cause it to wait for a response.
How can I override window.confirm to get consistent behavior?
Add this to OK action:
var href = $(obj).attr("href");
window.location.replace(href);
window.navigator.location(href);
return true;
And remove __postback line
it works with me
I want to show Confirmation Dialog when user saves any document from EDITForm.aspx. So I have written following JavaScript code.
function PreSaveAction() {
var _html = document.createElement();
_html.innerHTML = " <input type=\"button\" value=\"Submit\" onclick ='javascript:SubmitDlg();' /> <input type=\"button\" value=\"Cancel\" onclick =\"javascript:CloseDlg();\" /> </td> </tr> </tbody> </table>";
var options = {
title: "Confirm",
width: 400,
height: 200,
showClose: false,
allowMaximize: false,
autoSize: false,
html: _html
};
SP.UI.ModalDialog.showModalDialog(options);
}
function SubmitDlg() {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK);
}
function CloseDlg() {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.Cancel);
}
Now I have following queries.
SubmitDlg and CloseDlg is not fired when clicking on Submit or
Cancel.
Is this right way to Submit form (SubmitDlg method ) and Cancel dialog (CloseDlg method) from modal dialog ?
Also this modal dialog-box should be only appeared if no validation errors while saving record, means if any field-value is required and we have not put any value then it should display in-built red colored messages.
Thanks
in the options for the modal dialog you need to pass a reference to your call back function like this:
var opt = SP.UI.$create_DialogOptions();
opt.width = 500;
opt.height = 200;
opt.url = url;
opt.dialogReturnValueCallback = MyDialogClosed;
SP.UI.ModalDialog.showModalDialog(opt);
Then in your callback function you can check the status:
function MyDialogClosed(result, value) {
if (result == SP.UI.DialogResult.Cancel) {
//Cancel. Do whatever
}
else { //SP.UI.DialogResult.OK
//User clicked OK. You can pickup whatever was sent back in 'value' }
}
If you need to send stuff back from your dialog you can use this:
function okClicked()
{
SP.UI.ModalDialog.commonModalDialogClose(1, someobject);
}
To make this work you'd need to hook-up a function to the OK button in your server side code using something like this:
protected override void OnLoad(EventArgs e)
{
if (Master is DialogMaster)
{
var dm = Master as DialogMaster;
if(dm != null) dm.OkButton.Attributes.Add(#"onclick", #"return okClicked();");
}
base.OnLoad(e);
}
add class "CloseSPPopUp" to the btn u want to click to close
Add This Script to Page which has "CloseSPPopUp" btn
$('.CloseSPPopUp').click(function(){
window.top.CloseSPUIPopoup();
});
$('.CloseSPPopUp').click(function(){
window.top.CloseSPUIPopoup();
});
Now on Main Page where u are calling popup
function CloseSPUIPopoup{
$(".ms-dlgContent").hide();
}
Reason:
ms-dlgContent class is in Parent Page & CloseSPPopUp is in Iframe which is created at runtime
I am trying to avoid the confirm box of javascript and tried that jquery.ui dialog box.
When confirm box returns true or false after that only remaining javascipt will execute,but in this jquery.ui dialog that not happening.
This what i tried,
I am having some of the links
function checkit(){
var istrue = showdial("confirm");
if(istrue== true) alert("yes");
else alert("no");
}
function showdial(tStr)
{
$('<div></div>').appendTo('body')
.html('<div><h4>Are you sure..?</h4></div>')
.dialog({
title: tStr,
zIndex: 10000,
autoOpen: true,
modal: true,
buttons:{
Yes: function(){
$(this).dialog("close");
return true;
}
No: function(){
$(this).dialog("close");
return false;
}
}
});
}
Please correct me if i did anything wrong above.
Before clicking that yes or no button it always alerts "no" only, . How can i run a script after that dialog returns an value. And i dont want that setTimeout() function to use.
Asynchronous code can't return values like that. Look at this related question which explains how to resolve this problem using callbacks.