I'm trying to use a simple jquery-ui modal dialog as a delete confirmation in an ASP.NET C# application. I've done this many times before, but for some reason in this application it is misbehaving. I see the dialog pop up then it immediately disappears before I can click on either "Yes" or "No". Here's the relevant code (Javascript):
<script type="text/javascript" src="/resources/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="/resources/jquery-ui-1.9.1.custom.min.js"></script>
<link rel="stylesheet" type="text/css" href="/resources/ui-lightness/jquery-ui-1.9.1.custom.css" />
<script type="text/javascript">
var remConfirmed = false;
function ConfirmRemoveDialog(obj, title, dialogText) {
if (!remConfirmed) {
//add the dialog div to the page
$('body').append(String.Format("<div id='confirmRemoveDialog' title='{0}'><p>{1}</p></div>", title, dialogText));
//create the dialog
$('#confirmRemoveDialog').dialog({
modal: true,
resizable: false,
draggable: false,
close: function(event, ui) {
$('body').find('#confirmRemoveDialog').remove();
},
buttons:
{
'Yes, remove it': function() {
$(this).dialog('close');
remConfirmed = true;
if (obj) obj.click();
},
'No, keep it': function() {
$(this).dialog('close');
}
}
});
}
return remConfirmed;
}
//String.Format function (since Javascript doesn't have one built-in
String.Format = function() {
var s = arguments[0];
for (var i = 0; i < arguments.length - 1; i++) {
var reg = new RegExp("\\{" + i + "\\}", "gm");
s = s.replace(reg, arguments[i + 1]);
}
return s;
}
</script>
Here's where I'm using the confirmation function (in the OnClientClick of an <asp:Button> control):
<asp:Button ID="btnRemoveProgram" runat="server" Text="Remove" CausesValidation="false" OnClientClick="ConfirmRemoveDialog(this, 'Please confirm removal', 'Are you sure you wish to remove the selected Program? This cannot be undone.');" />
As I said, I've successfully used this same construct (nearly identical code) many times before; I don't know why it isn't working now. Any ideas will be greatly appreciated, I'm truly stumped on this one.
The runat="server" is telling the button that it should post back to perform events at the server. The OnClientClick will be executed before that on the client side, so you will see the dialog and then immediate the page posts, causing the dialog to disappear.
The problem is that your modal dialog box is not modal in the traditional windows sense. The javascript continues on. The simplest test is to add an alert right before your return, you will see it pops up right after the dialog is shown.
To get around this issue, return false always in the OnContentClick and then in your Yes/No button event handlers use the __doPostback javascript method.
You need to return the remConfirmed to the caller which is the button itself. On your button, do this:
OnClientClick="return ConfirmRemoveDialog(/* the rest of the code */);"
Related
I am using DOJO (1.7) together with ASP.NET. I have attached an onclick event to the submit button but am trying to validate on client side first. In plain javascript, if I used a 'return false' statement, that stopped the postback. However, returning false in the code does not stop the statement while using DOJO. I am a DOJO newbie and have no idea what to do. Thank you for your time.
require(["dojo/io/script", "dojo/on", "dojo/dom", "dojo/domReady!"],
function (script, on, dom) {
on(dom.byId("<%= btnSubmit.ClientID %>"), "click", function () {
dom.byId("<%= txtSellPercentage.ClientID %>").value = "farax";
return false;
}
)
});
I had to tweak the code a little. Apparently I was trying to call some event method without importing the particular script for events. So here goes
<script type="text/javascript">
require(["dojo/io/script", "dojo/on", "dojo/dom", "dojo/domReady!", "dojo/_base/event"],
function (script, on, dom, event) {
on(dom.byId("<%= btnSubmit.ClientID %>"), "click", function (e) {
dom.byId("<%= txtSellPercentage.ClientID %>").value = "farax";
event.stop(e);
}
)
});
</script>
I am using jquery onbeforeunload event in asp.net application.
If i write event as given below then its working fine and display confirm dialog box.
var vGlobal = true;
var sMessage = "Leaving the page will lost in unsaved data!";
[ Working ]
> window.onbeforeunload = function() {
> if (vGlobal == false) return
> sMessage; }
but its not working if i use bind method like as given below
[ Not working ]
$(window).bind("beforeunload", function(e) {
if (vGlobal == false)
return sMessage;
});
Anybody suggest me why its not working.Is there any difference between these two methods.
Code on aspx:
<asp:TextBox ID="txtName" runat="server"></asp:TextBox>
CLICK ON THIS LINK TO SEE RUNNING EXAMPLE
See the updated version
You need to bind all the events inside document ready event.
Apart from the fact that vGlobal is true and you are checking if (vGlobal == false), this smells like a $(document).ready() issue.
I.e. you should place the declaration inside a document.ready() handler as shown here:
$(document).ready(function(){
$(window).bind("beforeunload", function(e) {
if (vGlobal == false)
return sMessage;
});
});
There is no benefit in using jQuery to bind the event to the window - all you are doing is adding the overhead of having jQuery parse the window into a jQuery object, which you aren't even using.
Therefore, using:
window.onbeforeunload = handler;
Is preferable to using jQuery to bind this event.
You can still perform the binding inside of the document ready section:
$(document).ready(function () {
window.onbeforeunload = handler;
};
I've got a web form with a start date field. I've tied a jquery datepicker to the txt field. Now when I choose a date in FF, the selected date is populated in the text box and the calendar popup closes. However when I do the same thing in IE8, the selected date is populated in the text box but the popup remains open. I've also noticed that a script error is generated as soon as I select a date in the popup calendar.
I'm using jquery 1.3.2, jquery-ui 1.7.2, and .NET 3.5. Here's an example of my code:
<script type="text/javascript">
$(document).ready(function() {
$("#<%=txtStartDate.ClientID%>").datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
showOn: 'button',
buttonImage: '/_layouts/images/CALENDAR.GIF',
buttonImageOnly: true
});
});
</script>
<div id="stylized">
<asp:ValidationSummary ID="vs" runat="server" CssClass="messages-error" HeaderText=" Action required before the form can be submitted." ForeColor="" ValidationGroup="sh" />
<div class="formrow">
<div class="ms-formlabel formlabel">
<asp:Label ID="lblStartDate" runat="server" CssClass="ms-standardheader" AssociatedControlID="txtStartDate">Start Date:</asp:Label>
</div>
<div class="ms-formbody formfield">
<asp:RequiredFieldValidator ID="reqStartDate" runat="server" ControlToValidate="txtStartDate" ErrorMessage="Start Date is a required field." Text="*" Display="Dynamic" ValidationGroup="sh"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="cvStartDate" runat="server" ControlToValidate="txtStartDate" ErrorMessage="Date must be in the format MM/DD/YYYY" Text="*" Display="Dynamic" ValidationGroup="sh" Operator="DataTypeCheck" Type="Date"></asp:CompareValidator>
<asp:TextBox ID="txtStartDate" runat="server"></asp:TextBox>
<span class="formMessage">ex. MM/DD/YYYY</span>
</div>
</div>
<div id="buttonrow">
<asp:Button ID="btnSubmit" runat="server" Text="Submit" CssClass="ms-ButtonHeightWidth" OnClick="Submit_Click" ValidationGroup="sh" />
<asp:Button ID="btnCancel" runat="server" Text="Cancel" CssClass="ms-ButtonHeightWidth" OnClick="Cancel_Click" CausesValidation="false" />
</div>
</div>
Here's the script error I get in IE when I select the date:
'length' is null or not an object
WebResource.axd
Here's the code where the error is being thrown from:
function ValidatorOnChange(event) {
if (!event) {
event = window.event;
}
Page_InvalidControlToBeFocused = null;
var targetedControl;
if ((typeof(event.srcElement) != "undefined") && (event.srcElement != null)) {
targetedControl = event.srcElement;
}
else {
targetedControl = event.target;
}
var vals;
if (typeof(targetedControl.Validators) != "undefined") {
vals = targetedControl.Validators;
}
else {
if (targetedControl.tagName.toLowerCase() == "label") {
targetedControl = document.getElementById(targetedControl.htmlFor);
vals = targetedControl.Validators;
}
}
var i;
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
ValidatorUpdateIsValid();
}
It happens on the .length in the for loop at the end. Vals is null and isn't found in the previous if/else. I've stepped through the javascript and if (typeof(targetedControl.Validators) != "undefined") returns false and then if (targetedControl.tagName.toLowerCase() == "label") returns false too. Thus the length is null or not an object error.
Now I'm not sure if the datepicker popup not closing in IE and the script error in the WebResources.axd file are related errors, but I'm leaning that way. Can anyone tell me why the popup isn't closing?
As a date is selected, the datepicker triggers the change event on the INPUT element, but the ASP.Net validator picks up the click event instead, with the source an A element, and tries to find the validators on that A element, instead of the INPUT. This can be observed by inspecting event.srcElement inside the validator's ValidatorOnChange function. In browsers other than IE, event.type is 'change' and event.target is correctly the INPUT.
While the no-op function onSelect: function() { } prevents the error, by overriding the .change() built-in to the datepicker's default onSelect, it also prevents the validators from triggering. Here's a work-around for both:
onSelect: function() {
this.fireEvent && this.fireEvent('onchange') || $(this).change();
}
This uses the normal .change() trigger except on IE, where it's required to use .fireEvent to get the event object to be associated with the change and not the click.
It seems to be a bug of sorts, but adding this line in the datepicker declaration should solve it:
onSelect: function() {}
The solutions provided above only prevents the error from occurring.
On the datepicker:
onSelect : function(dateText, inst){ inst.input.trigger('cValidate')
and bind the event to the calendar input element.
.bind('cValidate', function (event) { window.ValidatorOnChange(event); });
this will fire the validatorchanged event with the correct event args (input field).
The reason
The root bug (I think it's probably meant to be a feature, or maybe a workaround for a known IE bug?) is in ASP.Net's ValidatorHookupEvent:
var func;
if (navigator.appName.toLowerCase().indexOf('explorer') > -1) {
func = new Function(functionPrefix + " " + ev);
}
else {
func = new Function("event", functionPrefix + " " + ev);
}
As a result, in the default case that there's no other onchange registered, this sets up the onchange for the input to be the equivalent of
function() { ValidatorOnChange(event); }
in IE and
function(event) { ValidatorOnChange(event); }
in other browsers. So iff you're using IE, the event passed to ValidatorOnChange will be window.event (since window is the global object).
A suggested solution
If you don't want to hack around with the ASP.Net scripts then I think the nicest way to handle this is to detect the broken event handler and replace it. As with other suggestions here, I offer an onSelect to include in the datepicker options.
onSelect: function(dateStr, datePicker) {
// http://stackoverflow.com/questions/1704398
if (datePicker.input[0].onchange.toString().match(/^[^(]+\(\)\s*{\s*ValidatorOnChange\(event\);\s*}\s*$/)) {
datePicker.input[0].onchange = ValidatorOnChange;
}
datePicker.input.trigger("change");
}
I'm applying this globally with
$.datepicker.setDefaults({
onSelect: function(dateStr, datePicker) {
etc.
}
});
It doesn't look like you're doing anything wrong since the ValidatorOnChange code is generated for you; there's something wrong in the way it's creating its vals object which appears to end up null on ie8.
It's been asked before, and the solution is overriding the onSelect function with a no-op function.
This is not the only kind of validator problem out there. Here's a vaguely similar issue with the autocomplete feature.
The fix...
onSelect: function() {}
..does not appear to work if the problem is with a CustomValidator that relies on a servewr side event handler to validate input.
There are a couple of other fixes mentioned here...
http://dev.jqueryui.com/ticket/4071
The problem is down to IE's event handling differing from other browsers and the client side validation code supplied by ASP Net not reacting gracefully to a situation not contemplated by it's authors.
This is an endemic problem with jQuery datepickers and ASP validation controls.
As you are saying, the wrong element cross-triggers an ASP NET javascript validation routine, and then the M$ code throws an error because the triggering element in the routine is undefined.
I solved this one differently from anyone else I have seen - by deciding that M$ should have written their code more robustly, and hence redeclaring some of the M$ validator code to cope with the undefined element. Everything else I have seen is essentially a workaround on the jQuery side, and cuts possible functionality out (eg. using the click event instead of change).
The bit that fails is
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
which throws an error when it tries to get a length for the undefined 'vals'.
I just added
if (vals) {
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
}
and she's good to go. Final code, which redeclares the entire offending function, is below. I put it as a script include at the bottom of my master page or page (so it occurs after the default declarations and replaces the earlier version).
Yes, this does break upwards compatibility if M$ decide to change their validator code in the future. But one would hope they'll fix it and then we can get rid of this patch altogether.
// Fix issue with datepicker and ASPNET validators: redeclare MS validator code with fix
function ValidatorOnChange(event) {
if (!event) {
event = window.event;
}
Page_InvalidControlToBeFocused = null;
var targetedControl;
if ((typeof (event.srcElement) != "undefined") && (event.srcElement != null)) {
targetedControl = event.srcElement;
}
else {
targetedControl = event.target;
}
var vals;
if (typeof (targetedControl.Validators) != "undefined") {
vals = targetedControl.Validators;
}
else {
if (targetedControl.tagName.toLowerCase() == "label") {
targetedControl = document.getElementById(targetedControl.htmlFor);
vals = targetedControl.Validators;
}
}
var i;
if (vals) {
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
}
ValidatorUpdateIsValid();
}
change jquery.ui.datepicker.js line 1504
'" href="#" >' + printDate.getDate() + '</a>')
with
'" href="javascript:DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);" >' + printDate.getDate() + '</a>')
test works OK!
I don't really know what the problem is, but I did notice that your does not have the ValidationGroup set, and both of your validators have that value set. You might try setting ValidationGroup="sh" in your TextBox and see if that helps.
Building upon the above answers and to provide further detail to my comment above,
Apparently in IE9+ and other browsers, you should now use dispatchEvent to fire the change event. (Why does .fireEvent() not work in IE9?)
The OnSelect function in the datepicker actually has 2 arguments:
The value of the textbox associated with the datepicker
An object with an id property that matches that of the textbox
mytextbox.datepicker({
defaultDate: null,
numberOfMonths: 1,
dateFormat: DisplayDateFormat,
onSelect: function (value, source) {
}
});
All the examples I saw used document.getElementById() to retrieve the textbox, which I thought wouldn't be necessary seeing as the source object has the same id as the textbox. Upon closer examination it turns out that source is an object, not the textbox element. I found the following code resolved the problem though:
mytextbox.datepicker({
defaultDate: null,
numberOfMonths: 1,
dateFormat: DisplayDateFormat,
onSelect: function (value, source) {
var ctrl = document.getElementById(source.id);
if ("dispatchEvent" in ctrl) {
// IE9
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
ctrl.dispatchEvent(evt);
} else if ("fireEvent" in ctrl) {
// IE7/IE8
ctrl.fireEvent("onchange");
} else {
$(ctrl).change();
}
}
});
Update: It appears that this approach is no longer working - not sure why. It stops the error from being thrown but doesn't trigger the change event.
Having this div:
<div id="advSearchDialog" style="visibility:hidden;">
<xx:search ID="searchUC" runat="server" />
</div>
And a button:
<input type="button" id="btnAdvSearch" value="Search" />
I turn it into a jQuery dialog, where the button opens the dialog:
$(document).ready(function() {
$('#advSearchDialog').dialog({
autoOpen: false,
height: 500,
width: 600,
modal: true,
bgiframe: true,
title: 'Avanceret søgning',
open: function(type, data) {
$(this).parent().appendTo("form");
}
});
$('#btnAdvSearch').click(function() {
$('#advSearchDialog').css('visibility', 'visible');
$('#advSearchDialog').dialog('open');
});
});
Using ASP.NET, I get a problem.
If I push some other button on the ASP.NET page (inside an update panel), and after that clicks the btnAdvSearch button, nothing happens. Why is that?
Thanks in advance
maybe the partial page refresh removes your click event, hard to say without seeing the whole page.
the solutions to that problem would be using jquery live events
http://docs.jquery.com/Events/live
hth
Check the emitted HTML using firebug or somthing similar and you will probably notice that your button is no longer inside the form tags and is at the end of the body tag.
In you're OK button callback you can use something like
dialogBox.appendTo($('#FormIdHere'));
dialogBox is a variable set as so
var dialogBox = $('#DialogDiv').dialog({ autoOpen: false });
This should add your button back into the form.
EDIT:
Here is a code snippet I've recently used (all the code below is fired within an onload function but reasonPostBack must be declared outside the onload function)
var button = $('input.rejectButton');
reasonPostBack = button.attr('onclick');
button.removeAttr('onclick');
var dialogBox = $('#ReasonDiv').dialog({ autoOpen: false, title: 'Please enter a reason', modal: true, bgiframe: true, buttons: { "Ok": function() {
if ($('input.reasonTextBox').val().length > 0) {
$(this).dialog('close');
dialogBox.appendTo($('#theform'));
reasonPostBack();
}
else
{
alert('You must enter a reason for rejection');
}
}
}
});
button.click(function() {
dialogBox.dialog('open');
return false;
});
First i take a reference to the .Net postback with
var reasonPostBack = button.attr('onclick');
and hold it for later then strip the click event from the button to stop the post back ocurring "automatically". I then build the dialog box and add an anonymous function for the OK button, this runs my code to test if there is anything in a text box, if there isn't it simply alerts the user otherwise it;
Closes the div
$(this).dialog('close');
Adds the div back inside the form tags ready for the post back
dialogBox.appendTo($('#theform'));
and then calls the original postback
reasonPostBack();
Finally the last bit of code
button.click(function() {
dialogBox.dialog('open');
return false;
});
adds our own event handler to the .Net button to open the dialog that was instantiated earlier.
HTH
OneSHOT
I have an ASP.NET page with a number of ASP:Button instances on it. For some, I need to show a confirmation prompt and, should the user choose yes, the original postback method is called. Otherwise, the overall process is cancelled.
I've got an example running but I get inconsistent results, mainly in FF3 where I get an exception thrown:
[Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame ::
I've looked this error up but I'm drawing a loss as to where I'm going wrong. Here's my example case. Note, for now I'm just using the css class as a lookup. Longer term I can embed the clientID of the control into my JS if it proves necessary :).
Html fragment:
<asp:Button ID="StartButton" runat="server" CssClass="startbutton" Text="Start" OnClick="OnStartClicked" />
Javascript:
$(".startbutton").each(function(){
$(document).data("startclick", $(this).get()[0].click);
$(this).unbind("click");
}).click(function(){
var oldclick = $(document).data("startclick");
alert("hello");
try
{
oldclick();
}
catch(err)
{
alert(err);
alert(err.description);
}
return false;
});
My code behind is relatively simple, the OnStart method simply executes a Response.Write
I've only just started looking into bind, unbind and trigger so my usage here is pretty much 'first time'.
Thanks for any help or advice.
S
EDIT:
This describes what I'm trying to do and also gives a run down of the kind of pitfalls:
http://www.nabble.com/onClick-prepend-td15194791s27240.html
How about this?
$(document).ready( function() {
$('.startbutton').click(function() {
return confirm('Are you sure?');
})
});
I've solved my problem for IE7 and FF3.
The trick is to make the postback work as an 'onclick' via an ASP.NET attribute on the button (see below). In Javascript this gets pulled out as a function reference when you read the click in JQuery.
To make it work, you then clear the onclick attribute (after saving it) and call it later on.
My code below shows it in action. This code isn't complete as I'm part way through making this into a generic prompt for my application. Its also a bit badly laid out! But at least it shows the principle.
ASP.NET button
<asp:Button ID="StartButton" runat="server" CssClass="startbutton" Text="Start" OnClick="OnStart" UseSubmitBehavior="false" />
Javascript:
$(".startbutton").each(function(){
$(document).data("startclick", $(this).attr("onclick"));
$(this).removeAttr("onclick");
}).click(function(){
$.blockUI({ message: $('#confirm'), css: { width: '383', cursor: 'auto' } });
$("#yes").click(function(){
$.unblockUI();
var oldclick = $(document).data("startclick");
try
{
oldclick();
}
catch(err)
{
alert(err);
alert(err.description);
}
});
$("#no").click(function(){
$.unblockUI();
});
return false;
});
Your problem comes from here :
$(document).data("startclick", $(this).get()[0].click);
...
var oldclick = $(document).data("startclick");
...
oldclick();
Here, you try to intercept a native event listener but there are two errors :
Using unbind will not remove the native event listener, just the ones added with jQuery
click is, AFAIK, a IE only method used to simulate a click, it not the event handler itself
You'll have to use onclick instead set its value to null instead of using unbind. Finally, don't store it in $(document).data(...), you'll have some problems when you add other buttons. Here is a sample code you can use :
$("selector").each(function()
{
var oldclick = this.onclick;
this.onclick = null;
$(this).click(function()
{
if (confirm("yes or no ?")) oldclick();
});
});
for mi works:
this.OnClientClick = "$.blockUI({ message: $('#ConfirmacionBOX'), css: { width: '275px' } });return false;";
This is a button (is a button class)