Search code examples
jqueryasp.netpostback

How to stop ASP.NET postback (return false, e.stopPropagation, e.cancelBubble) don't working


I can not stop ASP.NET postback in any case. Any known method (as return false, stopPropagation, cancelBubble) don't working. My code:

 <form method="post" action="./" id="Form1">
    <div onclick="watch_auc('617135a1d1c02a8fd9a22a72',false);">
 </form>
 <script>
    function watch_auc(idForm, watch) {
         jQuery.post(...);
         if (!e) var e = window.event;
         e.stopPropagation();
         e.cancelBubble = true;
         e.returnValue = false;
         return false;
   }
   function ajaxDone() { ... }
 </script>

My site also use jQuery and after I return from my function watch_auc() I see a huge jQuery event dispatcher what doing something misunderstanding for me. As a result jQuery generate postback. How to prevent this postback?

enter image description here


Solution

  • ok, lets put together a simple example to show how this works.

    We will put a simple button on the form, and pop up a dialog asking you yes, or no.

    So, first example, blocking code (halting code).

    this example works, because the js called HALTS waits for input, and then returns true or false.

    We have this button + markup:

            <asp:Button ID="cmdDelete" runat="server" Text="Delete Record" Width="112px" CssClass="btn"
                OnClick="cmdDelete_Click"  
                OnClientClick="return mydelprompt()"
             />
    
            <script>
    
                function mydelprompt() {
    
                    return confirm("Delete record? ok")
                }
    
            </script>
    

    So when we run above, we return value of true, or false for the OnCientClick event. If we return true, then the server side button (and post-back) will run.

    enter image description here

    And our server side code (that runs on post-back) is this:

        protected void cmdDelete_Click(object sender, EventArgs e)
        {
            Debug.Print("Server delete code will run");
            // server side code here to delete record
    
        }
    

    So, if we hit ok then a post back will occur (our button code server side runs).

    So if we hit cancel, then false is returned, and thus no post-back occurs, and server side code does not run.

    Ok, now lets replace the above confirm with a ajax call, or for simple, a jquery.UI dialog. (both really are the same issue).

    We now have this code:

            <script>
                function mydelprompt2(btn) {
    
                    var mydiv = $("#mydeldiv")
                    mydiv.dialog({
                        modal: true, appendTo: "form",
                        title: "delete", closeText: "",
                        width: "20%",
                        position: { my: 'left top', at: 'right bottom', of: btn },
                        buttons: {
                            Ok: (function () {
                                mydiv.dialog("close")
                                return true
                            }),
                            Cancel: (function () {
                                mydiv.dialog("close")
                                return false
                            })
                        }
    
                    });
                    return false;
                }
            </script>
    

    So, does or can the above work?

    NO!!! Why?

    When we click on our button, the above script runs, but is asyncrious - it runs RIGHT THROUGH without ANY halt or waiting of code, so the LAST LINE of the above script will return false, and our post-back does not occur, and CAN NEVER occur!!!

    The code inside of

     buttons: {
                            Ok: (function () {
                                mydiv.dialog("close")
                                return true
                            }),
                            Cancel: (function () {
                                mydiv.dialog("close")
                                return false
                            })
                        }
    

    Not relevant, since those are call backs. The code will run, display the dialog and ALSO have returned false to the button click, and thus not run.

    We will now see this:

    enter image description here

    However, the routine HAS ALREADY returned false - the last line of the script.

    When we hit ok or cancel, then either of those stubs can run - but we ALREADY returned false to the server side button - it will not run, and our ok/cancel does nothing.

    So, what is the solution here?

    As noted, since this js code is asynchronous, then it can't wait.

    There are two solutions I often use.

    One trick, is I create a hidden button below the actual button, hide it, and then click on it. So I will have this:

            <asp:Button ID="cmdDelete" runat="server" Text="Delete Record" Width="112px" CssClass="btn"
                OnClick="cmdDelete_Click"  
                OnClientClick="return mydelprompt2(this)"
             />
            <asp:Button ID="cmdDeleteH" runat="server" Text="Delete Record" Width="112px" CssClass="btn"
                OnClick="cmdDelete_Click"  
                Style="display:none"
                ClientIDMode="Static"
             />
    

    So, the 2nd button is hidden, and now our code is this:

                function mydelprompt2(btn) {
    
                    var mydiv = $("#mydeldiv")
                    mydiv.dialog({
                        modal: true, appendTo: "form",
                        title: "delete", closeText: "",
                        width: "20%",
                        position: { my: 'left top', at: 'right bottom', of: btn },
                        buttons: {
                            Ok: (function () {
                                mydiv.dialog("close")
                                $("#cmdDeleteH").click()
                            }),
                            Cancel: (function () {
                                mydiv.dialog("close")
                            })
                        }
    
                    });
                    return false;
                }
            </script>
    

    So, now if I hit ok, then I click the 2nd hidden button to run our code.

    This is not all that bad but often I don't like to have to add that 2nd fake hidden button and click on. But, the above now does work.

    If you hit ok, then post-back + button code works.

    If you hit cancel, then post-back + button code does not work

    We in effect really don't use the first button.

    However, there is a another way!

    I often now use this code, with just the one button.

            <script>
                mydelpromptok = false
                function mydelprompt2(btn) {
    
                    if (mydelpromptok) {
                        mydelpromptok = false
                        return true
                    }
    
                    var mydiv = $("#mydeldiv")
                    mydiv.dialog({
                        modal: true, appendTo: "form",
                        title: "delete", closeText: "",
                        width: "20%",
                        position: { my: 'left top', at: 'right bottom', of: btn },
                        buttons: {
                            Ok: (function () {
                                mydiv.dialog("close")
                                mydelpromptok = true
                                btn.click()
                            }),
                            Cancel: (function () {
                                mydiv.dialog("close")
                            })
                        }
    
                    });
                    return false;
                }
            </script>
    

    So note what we do here.

    The user clicks on button. The js (client side code) runs, pops the dialog (or does a ajax call, AND THEN AS NOTED RUNS RIGHT though to the end of the code and returns false.

    So, this means the server side code button can't run, did not run, and will not run.

    Now when the ajax call is done, returns (or in this case you answer the dialog), then we do this trick:

    Ok: (function () {
       mydiv.dialog("close")
       mydelpromptok = true
       btn.click()
    

    So we set that global var = true. and now RE-FIRE the sever side button!! And I had to pass the button anyway, since I wanted the button to appear right below the button click (and to the right) by using the jQuery position here.

    So, now what happens? The btn.click() fires the button, the button then call our SAME routine again but this time this occurs:

                mydelpromptok = false
                function mydelprompt2(btn) {
    
                    if (mydelpromptok) {
                        mydelpromptok = false
                        return true
                    }
    

    So, now the SAME routine is called again (btn.click()), but since we set the global var = true, then the routine at start checks this value, and since it is true, we return that value, and the server side button code now runs. (and note that mydelpromptok = false ONLY runs on the page load, and first initialization of variables - not later on, and not each time code is called).

    So, the same idea can be used with your code. When you return from the ajax call, set your flag = true, and "click()" that event again with the jQuery.Click() method. It will of course fire the routine to run again, and this time true is returned, and thus your server side button will run after the ajax call - even if the ajax call say takes 1-2 seconds, the code in a round about way waits, since the first time calling the js code DOES run through, does not halt (like most js code - rare exception was my first confirm() example, but that and alert() are about the only two things that actually halt js code.

    So, most routines - including ajax calls do NOT halt code. That routine you call will run RIGHT through to the end of that routine and exit. When the ajax call is done, then the success code stub will NOW re-enter, and be re-run. It is at that point you have to THEN call server side code. As noted, you can do this with a fake button, a _doPostback() js command, or do what I did above. Use a click method.

    Since in 9 out of 10 times, we want the button or click event to return true/false, then little harm occurred in fire the click event again, but this time we return true and the rest of that same routine does not run again.

    You can write code that flows better by considering use of a "promise" in js, but you wind up with at least two separate routines, and you STILL have to find a way to trigger/call that click event. Other approaches involve "cancel event" or stop propagation of the button - but they can be messy to work with.

    So, either extra hidden button - and click it when your ajax success runs, or stick to one simple event, and introduce that true/false flag.

    I find for adding a confirm/yes/no dialog to existing asp.net buttons and click events the above approach works VERY well, since the button code, and original button event needs ZERO changes except for the addition of the client side click event, and that of returning true/false.

    Give the above idea a try.

    But, by non-blocking code, I simple mean that those js routines do NOT halt, run right though, and they are to be considered asynchronous code.

    so in your example code, you need the last line to be return false so the button click does not run. You have to click again, and at the start of the routine return true and exit if you want the post back to run. Your code that follows to set true/false is of no value UNLESS we click the button or trigger that event again, since on first click - the js routine you have DOES NOT halt, nor wait - it runs right though to the end, and that's too late to return true/false to the sever side button/click event.