views:

1786

answers:

9

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?

A: 

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.

KevnRoberts
+5  A: 

It seems to be a bug of sorts, but adding this line in the datepicker declaration should solve it:

onSelect: function() {}
Marek Karbarz
+1  A: 

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.

dlamblin
+1  A: 

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.

Fentex
+1  A: 

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.

rdworth
This worked for me, much better than a noop in onSelect:
Redbeard 0x0A
A: 

Yes onSelect() with empty declaration solve the problem. Find more about it here. http://praveenbattula.blogspot.com/2009/09/jquery-datepicker-problem-on-date.html

Rare Solutions
A: 

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();
}
Ben McIntyre
A: 

I tried below but it wasn't working for me.

$(document).ready(function(){
        $('.date-pick').datePicker(
            {
                startDate: '01/01/1970',
                endDate: (new Date()).addDays(1).asString(),
                          onSelect: function() {} 
            });
     });

Please do let me know if I am making any mistake !!!

Mayank Parmar
A: 

change jquery.ui.datepicker.js line 1504

'" href="#" >' + printDate.getDate() + '')

with

'" href="javascript:DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' + inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);" >' + printDate.getDate() + '')

test works OK!

changcn