The Click Event Always Fires Twice

Here’s the situation:

You have an ASP:Button inside an ASP:UpdatePanel, but also want to go modal when the button is pressed.  This means setting up a jQuery function to handle the click event.  You can’t just switch the ASP:Button to and HTML button because you want to control the button visibility from the code behind.

The jQuery function needs to ask for confirmation, make the page modal, and the do a __doPostBack() all without killing the modal until the postback is done.

Still with me?

Here’s the problem: this entire mess of firing a server control click event through jQuery from within an updatepanel causes the whole page to postback not once, but twice.

Starting with the button the code looks like this (this listing is not complete and only intended to show the problem)

<asp:UpdatePanel runat="server" ID="myUpdatePanel" UpdateMode="Conditional" >
    <ContentTemplate>
        <asp:Button runat="server" ID="btnAddNew" CausesValidation="False" ClientIDMode="Static" />
    </ContentTemplate>
</asp:UpdatePanel>

As you can see, there’s nothing fancy about the button.  Click the button and a new record is created.  But, the operation takes a few seconds so we’d like to make the page modal while it’s creating the record.  Enter jQuery.

 <script language="javascript" type="text/javascript">
    $(document).ready(function () {      
        $("#btnAddNew").click(function (event) {
            try {               
                if (confirm("Are you sure you want to create a new record?")) {
                    $.blockUI({
                        message: "<h2>Creating new record, please wait.</h2>"
                    });
                    event.preventDefault();
                    __doPostBack('newRecord', {an argument variable can go here if needed});
                } else {
                    return false;
                }
            } catch (e) {
                alert(e);
            }
        });
</script>

In the code above you see the click event to the button is wired up on document ready.  It confirms the user intends to add a new record.  If the answer is yes button default is prevented and the __doPostBack is fired.

In order to capture the __doPostBack we’re going to use the EventTarget and EventArgument session variables.

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim eventTarget As String = Request("__EVENTTARGET")
    Dim eventArgument As String = Request("__EVENTARGUMENT")
   Select Case eventTarget                        
        Case "newRecord"
            btnAddNew_Click()
    End Select
End Sub

In the page load event, capture the EventTarget and EventArgument.  If the EventTarget matches run the necessary function, in this case btnAddNew_Click().

As a side note, I normally use Select Case where I can, but in this simple example you could also use If…then.

The btnAddNew_Click is whatever you need to run.

Sub btnAddNew_Click()
   {your code to add a record goes here}
End Sub

The problem occurs back in the jQuery.  Once the jQuery fires the postback, the PageLoad event is fired and if your Target is set right that will fire the btnAddNew_Click routine.  When that completes control returns to the updatepanel which now needs to update itself and this fires the pageload event and since the Target is still in memory the btnAddNew_click code fires again.

To stop the second run of events we only need to add one line of code to the jQuery btnAddNew click function.

return false;

This should be placed right after the __doPostBack call so that our jQuery code now looks like this:

<script language="javascript" type="text/javascript">
    $(document).ready(function () {      
        $("#btnAddNew").click(function (event) {
            try {               
                if (confirm("Are you sure you want to create a new record?")) {
                    $.blockUI({
                        message: "<h2>Creating new record, please wait.</h2>"
                    });
                    event.preventDefault();
                    __doPostBack('newRecord', {an argument variable can go here if needed});
                    return false;
                } else {
                    return false;
                }
            } catch (e) {
                alert(e);
            }
        });
</script>

It’s almost hard to see, but it’s there. Return false stops the updatepanel update event from firing. Lo and behold, the click event now only fires once.

Leave a Reply