Welcome to AspAdvice Sign in | Join | Help

.Net Discoveries

An attempt to pass along some answers I have discovered in my .Net coding.
Setting Focus to a Control in a ModalPopupExtender

Prologue

I’ve found that we quite often use the ModalPopupExtender included in the Ajax Control Toolkit on our internal intranet site. We have a number of places where users have requested that since they use it so often that we have the cursor go to a specific field when the popup is displayed. This isn’t quite as straightforward for us as it sounds.

Problem

Since the ModalPopupExtender is a client-side code piece, it isn’t as straightforward as it sounds to put code in the set the control focus. While our site usually uses an UpdatePanel so that we can do a partial postback and do some processing and then display the ModalPopup from the code-behind, we can’t just use the .Focus() method when calling a ModalPopup, for us it doesn’t work.

I’ve tested several different things in other smaller applications and found that it seems to not be an issue on smaller lightweight pages, however, our site has some rather complex ModalPopups and they are on rather complex pages. For some reason we can’t just use the .Focus() method of the textbox and have it work. Our issue seems to be a slight delay in processing, basically the .Focus() method get’s called/run before the ModalPopup is ready and so focus isn’t given.

In this post, we’ll look put together a simple workable JavaScript solution that is written all in code-behind.

Solution

To get started, let’s create a small page with a Panel and ModalPopupExtender. We’ll also create a LinkButton to show the ModalPopup. Create a new .aspx page with the following HTML code:

<ajaxToolkit:ToolkitScriptManager ID="atScriptManager" runat="server" /> 
   <asp:UpdatePanel ID="upnlEverything" runat="server">
      <ContentTemplate>
        <asp:LinkButton ID="lnkbtnShowModal" runat="server"
                Text="Add Something" />
        <asp:Panel ID="pnlTest" runat="server" BorderColor="Red"
                      BorderStyle="Solid" BorderWidth="2">
            <asp:TextBox ID="txtTest" runat="server" /><br />
            <asp:LinkButton ID="lnkbtnClose" runat="server" Text="Close" />
        </asp:Panel>
        <asp:Button ID="btnFakeMPEButton" runat="server"
                      style="display:none;" />
        <ajaxToolkit:ModalPopupExtender ID="mpeThePopup" runat="server"
            TargetControlID="btnFakeMPEButton"
            PopupControlID="pnlTest" />
    </ContentTemplate>
</asp:UpdatePanel>

Note: I have previously registered my Ajax Control Toolkit in the Web.config so that I don’t have to explicitly register it on each page, and I created my own prefix for it (ajaxToolkit).

The code is pretty straight forward, I have created a LinkButton (lnkbtnShowModal) that I’ll use to display the ModalPopup from the code-behind. The ModalPopupExtender properties can be set to acknowledge the link and skip the code-behind piece, however we usually do some processing behind the scenes before we display the ModalPopup so I usually create a fake button (btnFakeMPEButton) that I feed the ModalPopupExtender since it won’t run without one.

In the panel we’re going to be extending, there’s one textbox (txtTest) and one LinkButton for closing the dialog (lnkbtnClose). Our object will be to set the focus to the text box when we display the ModalPopup. I’ve also added a little formatting to the panel just so that it’s more visible on our page.

Finally, we’ll set up a little back-end code so that when we click lnkbtnShowModal, the ModalPopup will be displayed. In the code-behind, add the following line to lnkbtnShowModal’s Click event handler:

mpeThePopup.Show()

Currently, if we run our application, we’ll see that the link will open the ModalPopup, but that the textbox is NOT set to focus. Since our code-behind gives us the ability to set focus to controls, it seems like this would be a good way to go. But this it isn’t working for us, so we’ve created some JavaScript to do it. Let’s create a new subroutine in our code-behind and add some JavaScript to our page as it is rendered.

Private Sub AddJavaScript()
    Dim scriptBlock As New StringBuilder() 

    scriptBlock.Append("<script type=""text/javascript"">" & vbCrLf)
    scriptBlock.Append("    Sys.Application.add_load(function() {" & vbCrLf)
    scriptBlock.Append("        var thePopup = $find('" & _
                   mpeThePopup.ClientID & "');" & vbCrLf)
    scriptBlock.Append("        thePopup.add_shown( _
                   function() {popupFocusTimer();});" & vbCrLf) 

    scriptBlock.Append("        function popupFocusTimer() _
             { setTimeout(popupFocus,300); }" & vbCrLf)
    scriptBlock.Append("        function popupFocus() _
     { document.getElementById('" & txtTest.ClientID & "').focus();}" & vbCrLf)
    scriptBlock.Append("   });" & vbCrLf) 

    scriptBlock.Append("</script>" & vbCrLf)
    If (Not Page.ClientScript.IsStartupScriptRegistered("setFocus")) Then
        Page.ClientScript.RegisterStartupScript(Me.GetType(), "setFocus", scriptBlock.ToString())
    End If
End Sub

This subroutine will create a script block and add the appropriate JavaScript code to set our focus. We found in our environment that we had to add a slight delay before setting focus, so when the link is clicked, we actually call setTimeout and pass in the function that does the actual focus call to the setTimeout function.

The Sys.Application.add_load() call basically runs this enclosed function when the page is finished loading. This ensures that everything is on the page and ready before the code is run. Within the Sys.Application function, we retrieve the ModalPopup as an object and add an event handler for when it is shown. The add_shown event handler is triggered when the dialog is shown. We’ll listen for this event and then we’ll start the timer function.

The next section creates two functions. One that sets a timer for .3 seconds and then calls the other, which actually does the call to the JavaScript focus() method. Notice that since we’re in the code-behind, we can easily retrieve the control’s clientID and enter it into the code.

In the final section, we add this code to the page by using the Page.ClientScript.IsStartupScriptRegistered method. This allows us to help keep from getting the code added more than once and giving us errors for multiple functions name the same etc.

Finally, add the following line to your Page_Load event handler to run our AddJavaScript subroutine:

AddJavaScript()

Now if you run your application, when you click the lnkbtnShowModal link, you’ll see that the Textbox receives the focus.

Epilogue

While many people will find it no problem to use the .Focus() method in the code-behind, we’ve found it problematic in our environment due to page complexity and load times. This has been a simple yet effective way for us to work around that issue.

Sponsor
Posted: Wednesday, April 03, 2013 10:14 AM by Yougotiger

Comments

No Comments

Leave a Comment

(required) 

(required) 

(optional)

(required) 

Enter the code you see below

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS