views:

745

answers:

4

I've been trying to integrate the jQuery UI Datepicker into our ASP.NET WebForms application. The application uses master pages to provide a common look to all pages, and all of the content pages are built inside the ContentTemplate of an UpdatePanel. I've created a user control to wrap the datepicker's functionality and allow setting of the minDate, maxDate, validators, etc. for each date from the codebehind at runtime. I also need to deal with the way ASP.NET generates client element IDs.

Over the last week, I've searched high and low, and found lots of tips for getting it to work. Here is a somewhat simplified version of where I'm at right now.

<asp:TextBox ID="txtTB" runat="server"
    MaxLength="10"
    CssClass="dateBox" />

<script type="text/javascript">

    // This function enables the datepicker behavior for this textbox by its ClientID.
    function <%=txtTB.ClientID %>() {
        $("#<%=txtTB.ClientID %>").datepicker({
            changeMonth: true, changeYear: true,
            showOn: 'button',
            buttonImage: "<%=Request.ApplicationPath %>/images/calendarIcon.gif",
            buttonImageOnly: true, buttonText: '', duration: '',
            onSelect: function() { }
        });
    };

    // Register the above function to execute on initial page load...
    $(document).ready(function(){ <%=txtTB.ClientID %>(); }) ;

    // ...and also after any update panel it's on has been refreshed. 
    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(<%=txtTB.ClientID %>);

</script>

I've left out the validators and some other markup that I don't think is related to the issue, but that's the meat of the user control--a textbox, and the jQuery script that enables the datepicker functionality. The basic idea is to leverage ASP.NET's client IDs to:

  1. Provide a unique function name for the JavaScript function for this specific control
  2. Register that function with jQuery to enable the datepicker after the initial page load
  3. Register that same function with ASP.NET's PageRequestManager to keep the datepickers enabled after postbacks

Items 1 and 2 are working great. However, after a postback, the datepicker functionality is lost and I'm left with just a textbox.

But wait! That's not all. A given page consists of multiple panels, only one of which is visible at a time. These are selected by only having the Visible property true for the current panel. The Visible property for all of other panels are set to false.

Now get this: The datepickers on the first panel, the one displayed upon initial page load, work as expected. Those on the second panel just don't show up. Going back to the first page, the datepickers show up again.

Does anyone have any ideas where I'm going wrong?

A: 

When you set a control's Visible property to false, it doesn't get rendered at all.

That means that the Javascript inside the invisible panels did not exist when the page was first loaded.

To solve this, you can hide your panels using CSS (display: none) instead of the Visible property.

SLaks
Right, I was aware of that, and thought it might be relevant, which is why I included that in my question. But I'm still not sure why the PageRequestManager doesn't run the functions to setup datepicker functionality for the user controls on the panel that **is** being rendered? Or does the broswer not "see" the new scripts for the new date controls after a postback? If that's the case, I'm going to need another approach, but using the display:none option would make my pages just huge. (They're already well over 300-400K.)
JeffK
+1  A: 

I think a cleaner way to do this is to use ClientScriptManager.RegisterStartupScript.

Javascript:

function initCalendar(controlId) {
    $("#" + controlId).blahblah(....
}

In your code behind (OnPreRender perhaps):

Page.ClientScript.RegisterStartupScript(this.GetType(), "SomeName", string.Format("<script>initCalendar('{0}');</script>", txtBox.ClientID));
Chetan Sastry
I'll give this a try. Looks promising. Does this eliminate the need to do the$(document).ready(function(){ <%=txtTB.ClientID %>(); });
JeffK
Depends on where you put the `RegisterStartupScript`. Just ensure you call it on page load and on switching tabs. Then you don't need the `$(document).ready...`. It just puts a script block at the end of your form to be executed upon parse. Obviously, jQuery and its plugins must be loaded by then. It doesn't probably work if you load them at the end of your page.
Chetan Sastry
A: 

While $(document).ready() is ideal for one-time initialization routines, it leaves you hanging if you have code that needs to be re-run after every partial postback. The LiveQuery functionality added in jQuery v1.3+ helps with this, but only works for a limited set of functionality.

For example, what if we wanted to add a jQueryUI datepicker to the TextBox in the previous example? Adding it in $(document).ready() would work great, until a partial postback occurred. Then, the UpdatePanel’s new TextBox element would no longer have the datepicker wired up to it.

<script type="text/javascript">
  function pageLoad() {
    $('#TextBox1').unbind();
    $('#TextBox1').datepicker(); 
  }
</script>

<asp:ScriptManager runat="server" />

<asp:UpdatePanel runat="server">
  <ContentTemplate>
    <asp:Button runat="server" ID="Button1" />
    <asp:TextBox runat="server" ID="TextBox1" />
  </ContentTemplate>
</asp:UpdatePanel>

This above Answer is taken from the below link. I have tested and implemented this in one of my project.

http://encosia.com/2009/03/25/document-ready-and-pageload-are-not-the-same/

Vipin
Thanks for this. The content behind that link reads like this is really the solution I'm looking for, Unfortunately, I've had to move on to other functionality for our application. When we get the current version out and start on the next release, I'll definitely revisit the datepicker and try this out. I'll mark it as "the answer" if it works.
JeffK
A: 

Try this inside the update panel

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>

        <script type="text/javascript">
        var prm = Sys.WebForms.PageRequestManager.getInstance();

        prm.add_endRequest(function() {
            var customer = document.getElementById("<%=cmbCustomers.ClientID%>").value;

            /* Jquery Functions Here*/
            $(document).ready(function() {
               ...
            });


        });
        </script>
Manuel Vázquez