SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    Barefoot on the Moon! silver trophy
    Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,528
    Mentioned
    52 Post(s)
    Tagged
    1 Thread(s)

    [jQuery] Confirmation Dialog Upon Submission

    I'm trying to get a confirmation dialog to appear when a form is submitted, but I've actually been having quite a lot of difficulty in getting it to work.

    Here's what should happen:

    1) The user clicks the "purge logs" submit button
    2) A confirmation dialog appears
    3) If the user clicks the "yes" button, the form is submitted. If the user clicks the "no" button or "close" button, nothing happens.

    Here's what actually happens:
    The forms submits itself without waiting for the user to click yes or no in the dialog that appears.

    Here's the code:

    Code:
    <html>
    <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
    <script type="text/javascript">
    
    $().ready(function(){
    
    
            $('form').submit(function(e){
    
                var confirm = ConfirmDialog('Confirm', 'Are you sure?');
    
                if(confirm){
                    form.submit();
                }
    
                
                
            });
                
            function ConfirmDialog(title,message){
                
                var confirmdialog = $('<div></div>').appendTo('body')
                .html('<div><h6>'+message+'</h6></div>')
                .dialog({
                    modal: true, title: title, zIndex: 10000, autoOpen: false,
                    width: 'auto', resizable: false,
                    buttons: {
                        Yes: function(){
                            $(this).dialog("close");
                            return true;
                        },
                        No: function(){
                            $(this).dialog("close");
                            return false;
                        }
                    },
                    close: function(event, ui){
                        $(this).remove();
                        return false;
                    }
                });
    
    
                return confirmdialog.dialog("open");
        
            }
    });
        
    
    </script>
    </head>
    <body>
    <form id="form_purge" name="form_purge" method="post" action="test.php">
    <button type="submit" name="submit_purge" id="submit_purge">Purge&nbsp;Logs</button>
    </form>
    </html>
    Visit The Blog | Follow On Twitter
    301tool 1.1.5 - URL redirector & shortener (PHP/MySQL)
    Can be hosted on and utilize your own domain

  2. #2
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,358
    Mentioned
    179 Post(s)
    Tagged
    9 Thread(s)
    Hi Force Flow,

    The problem with your original script is that when the form is submitted, the variable confirm is being assigned a jQuery object containing your ConfirmDialog, which then evaluates to true, thus causing the form to be submitted.

    You can check this by preventing the form's default action and logging the value of confirm to the console:

    Code JavaScript:
    $('form').submit(function(e){
      e.preventDefault();
      var confirm = ConfirmDialog('Confirm', 'Are you sure?');
      console.log(confirm[0]);
    });

    outputs:

    HTML Code:
    <div id="ui-id-1" class="ui-dialog-content ui-widget-content" style="width: auto; min-height: 73px; max-height: none; height: auto;">
      <div>
        <h6>Are you sure?</h6>
      </div>
    </div>
    regardless of what the user clicks.

    I'm sure I'm overthinking things here, but one way to get around this would be to use a promise, which will only be resolved once the user has clicked "Yes".

    Here's an example:

    Code:
    <!DOCTYPE HTML>
    <html>
      <head>
        <meta charset="utf-8">
        <title>jQuery form</title>
      </head>
      
      <body>
        <form id="form_purge" name="form_purge" method="post" action="test.php">
          <button type="submit" name="submit_purge" id="submit_purge">Purge&nbsp;Logs</button>
        </form>
        
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
        <script type="text/javascript">
          var deferred = new $.Deferred(),
              promise = deferred.promise();
          
          $("form").submit(function(e){
            var self = this;
            e.preventDefault();
            promise.done( function(){self.submit();});
            return ConfirmDialog('Confirm', 'Are you sure?');
          });
          
          function ConfirmDialog(title,message){
            var confirmdialog = $('<div></div>').appendTo('body')
            .html('<div><h6>'+message+'</h6></div>')
            .dialog({
              modal: true, title: title, zIndex: 10000, autoOpen: false,
              width: 'auto', resizable: false,
              buttons: {
                Yes: function(){
                  deferred.resolve();
                  $(this).dialog("close");
                },
                No: function(){
                  $(this).dialog("close");
                }
              },
              close: function(event, ui){
                $(this).remove();
                return false;
              }
            });
            return confirmdialog.dialog("open");
          }
        </script>
      </body>
    </html>
    I hope that helps you.

    I would also be glad to hear suggestions from anyone else as to how one might solve this.

  3. #3
    Barefoot on the Moon! silver trophy
    Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,528
    Mentioned
    52 Post(s)
    Tagged
    1 Thread(s)
    I attempted to run your script, but for some reason, it didn't actually work. [edit: nevermind, I got it working]

    In any case, after quite a bit of tinkering, I eventually came up with this:

    Code:
    <html><head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
    <script type="text/javascript">
    
    
    $().ready(function(){
    
        //when a form is submitted
        $('form').submit(function(e){
    
            //if a hidden input named confirmed exists in the form, display yes/no dialog
            if($('form input[name=confirm][type=hidden]').val()){
    
                e.preventDefault();
    
                var form = $(this);
                
                //since the submit button is not passed, recreate the name/value
                $("input[type=submit], input[type=button], button", form).eq(0).each(function(){
                    var self = $(this);
                    var tempElement = $("<input type='hidden'/>");
    
                    // clone the important parts of the button used to submit the form.
                    tempElement
                        .attr("name", this.name)
                        .val(self.val())
                        .appendTo(form);
                });
    
                //call the confirm dialog
                ConfirmDialog('Confirm', 'Are you sure?', this);
            }
        });
    
        
        function ConfirmDialog(title,message,form){    
                
            var confirmdialog = $('<div></div>').appendTo('body')
                .html('<div><h6>'+message+'</h6></div>')
                .dialog({
                    modal: true, title: title, zIndex: 10000, autoOpen: false,
                    width: 'auto', resizable: false,
                    buttons: {
                        Yes: function(){
                            //submit the form
                            form.submit();
                            $(this).dialog("close");
                        },
                        No: function(){
                            $(this).dialog("close");
                        }
                    },
                    close: function(event, ui){
                        $(this).remove();
                    }
                });
    
    
            confirmdialog.dialog("open");
        }
        
        
    });
    
    </script>
    </head>
    <body>
    <form id="form_purge" name="form_purge" method="post" action="test.php">
    <button type="submit" name="submit_purge" id="submit_purge">Purge&nbsp;Logs</button>
    <input type="hidden" name="confirm" value="true">
    </form>
    </html>
    The whole problem here is that the preventDefault() function needs to be used on an event. Since a form's onsubmit attribute can't pass an event, I had to use some javascript magic to trigger when a form submission was triggered.

    Since I had to use $('form').submit(), it was too generic since it caught *all* form submissions. However, it's not ideal to define every form I need the dialog for in the submission trigger. So, I put a hidden input element in the forms that I needed the dialog for, and checked for it.

    One interesting thing was that when javascript submits the form, the submit button that originally triggered the submit didn't actually get passed in the form's data, so I had to add it as a hidden element.

    Also, this form can be submitted with or without javascript without any extra code on the server-side, which is a plus.

    I'm not sure if this is the best approach or not, so if anyone has other suggestions, I'd be happy to see them.
    Visit The Blog | Follow On Twitter
    301tool 1.1.5 - URL redirector & shortener (PHP/MySQL)
    Can be hosted on and utilize your own domain

  4. #4
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,358
    Mentioned
    179 Post(s)
    Tagged
    9 Thread(s)
    Quote Originally Posted by Force Flow View Post
    I attempted to run your script, but for some reason, it didn't actually work.
    Oops sorry, I was messing around with it for a couple of minutes after posting.
    Here's a demo of it working: http://hibbard.eu/blog/pages/form-with-promise.html

    Would you do me a favour and check if that works for you.
    Theoretically it should be cross-browser compatible.

  5. #5
    Barefoot on the Moon! silver trophy
    Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,528
    Mentioned
    52 Post(s)
    Tagged
    1 Thread(s)
    I made a few tweaks to Pullo's code, but overall, a much more compact solution than what I came up with

    Code:
    $().ready(function(){
        var deferred = new $.Deferred();
        var promise = deferred.promise();
        
        $("form").submit(function(e){
            //if a hidden input named confirmed exists in the form, display yes/no dialog
            if($('form input[name=confirm][type=hidden]').val()){
                var self = this;
                e.preventDefault();
                promise.done(function(){self.submit();});
                ConfirmDialog('Confirm', 'Are you sure?');
            }
        });
        
        function ConfirmDialog(title,message){
            var confirmdialog = $('<div></div>').appendTo('body')
                .html('<div><h6>'+message+'</h6></div>')
                .dialog({
                    modal: true, title: title, zIndex: 10000, autoOpen: false,
                    width: 'auto', resizable: false,
                    buttons: {
                        Yes: function(){
                            deferred.resolve();
                            $(this).dialog("close");
                        },
                        No: function(){
                            $(this).dialog("close");
                        }
                    },
                    close: function(event, ui){
                        $(this).remove();
                    }
                });
            confirmdialog.dialog("open");
        }
        
        
    });
    Visit The Blog | Follow On Twitter
    301tool 1.1.5 - URL redirector & shortener (PHP/MySQL)
    Can be hosted on and utilize your own domain

  6. #6
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,358
    Mentioned
    179 Post(s)
    Tagged
    9 Thread(s)
    Good stuff
    I'm only just getting my head around deferreds/promises/futures etc, but they are proving to be pretty useful.

  7. #7
    Barefoot on the Moon! silver trophy
    Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,528
    Mentioned
    52 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Pullo View Post
    Good stuff
    I'm only just getting my head around deferreds/promises/futures etc, but they are proving to be pretty useful.
    I don't use javascript all that much beyond basic validation and UI stuff, so I'm very much unaware of some of the more advanced jQuery features like deferred/promise.

    Thanks

    [edit]: Drat, I just realized that the submit button isn't included in the form data sent to the server. I'll have to add the code block that recreated it as a hidden element.

    [edit2]: The new code:

    Code:
    $().ready(function(){
        
        var deferred = new $.Deferred();
        var promise = deferred.promise();
        
        $("form").submit(function(e){
            //if a hidden input named confirmed exists in the form, display yes/no dialog
            if($('form input[name=confirm][type=hidden]').val()){
                var form = this;
                e.preventDefault();
                
                //since the submit button is not passed, recreate the name/value pair as hidden element
                $("input[type=submit], input[type=button], button", form).eq(0).each(function(){
                    var self = $(this);
                    var tempElement = $("<input type='hidden'/>");
    
                    //clone the important parts of the button used to submit the form.
                    tempElement
                        .attr("name", this.name)
                        .val(self.val())
                        .appendTo(form);
                });
                
                promise.done(function(){form.submit();});
                ConfirmDialog('Confirm', 'Are you sure?');
            }
        });
        
        function ConfirmDialog(title,message){
            var confirmdialog = $('<div></div>').appendTo('body')
                .html('<div><h6>'+message+'</h6></div>')
                .dialog({
                    modal: true, title: title, zIndex: 10000, autoOpen: false,
                    width: 'auto', resizable: false,
                    buttons: {
                        Yes: function(){
                            deferred.resolve();
                            $(this).dialog("close");
                        },
                        No: function(){
                            $(this).dialog("close");
                        }
                    },
                    close: function(event, ui){
                        $(this).remove();
                    }
                });
            confirmdialog.dialog("open");
        }
        
        
    });
    Last edited by Force Flow; Jul 3, 2013 at 11:51. Reason: new code
    Visit The Blog | Follow On Twitter
    301tool 1.1.5 - URL redirector & shortener (PHP/MySQL)
    Can be hosted on and utilize your own domain

  8. #8
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,527
    Mentioned
    84 Post(s)
    Tagged
    4 Thread(s)
    It may just be me, but I think that some overthinking may have been occurring here.
    Can't you just pass a success function to the ConfirmDialog function, which will be run when the Yes button is pressed?

    Here's the setup, where we prevent the default submit action, this time, and we save off a reference to the form so that we can then trigger an actual submit event later on from that function being passed to ConfirmDialog:

    Code javascript:
    $('form').on('submit', function (e) {
        e.preventDefault();
        var form = this;
     
        confirm = confirmDialog('Confirm', 'Are you sure?', function () {
            form.submit();
        });
    });

    And here's the payoff, where we decide out if we want to to run that success function or not:

    Code javascript:
    function confirmDialog(title, message, success) {
        ...
                Yes: function () {
                    success();
                    $(this).dialog("close");
                },
                No: function () {
                    $(this).dialog("close");
                }
        ...
    }

    You can see the code in action at http://jsfiddle.net/pmw57/67Ge2/

    I have also taken the liberty to run the code through jslint.com to help weed out any issues there. Seeing function names with a capital first letter cause me to go *twitch*
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  9. #9
    Barefoot on the Moon! silver trophy
    Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,528
    Mentioned
    52 Post(s)
    Tagged
    1 Thread(s)
    The submit button "submit_purge" is still missing from the form data with that method.

    I never would've thought of putting a function in passed variable and calling it like that. It's certainly a less convoluted approach.

    [edit]: I reworked your code to include a few things from the code I posted earlier

    Code:
    $().ready(function(){
        
        $('form').submit(function(e){
            
            //if a hidden input named confirmed exists in the form, display yes/no dialog
            if($('form input[name=confirm][type=hidden]').val()){
                e.preventDefault();
                var form = this;
                
              //since the submit button is not passed, recreate the name/value pair as hidden element
                $("button[type=submit], input[type=submit], button", form).eq(0).each(function(){
                    var self = $(this);
                    var tempElement = $('<input type="hidden">');
        
                    //clone the important parts of the button used to submit the form.
                    tempElement
                        .attr("name", this.name)
                        .val(self.val())
                        .appendTo(form);
                });
                
                ConfirmDialog('Confirm', 'Are you sure?', function () {
                    form.submit();
                });
            }
            
        });
        
        function ConfirmDialog(title, message, success){
            var confirmdialog = $('<div></div>').appendTo('body')
            .html('<div><h6>'+message+'</h6></div>')
            .dialog({
                modal: true, title: title, zIndex: 10000, autoOpen: false,
                width: 'auto', resizable: false,
                buttons: {
                    Yes: function(){
                        success();
                        $(this).dialog("close");
                    },
                    No: function(){
                        $(this).dialog("close");
                    }
                },
                close: function(event, ui){
                    $(this).remove();
                }
            });
            
            confirmdialog.dialog("open");
        }
    });
    Visit The Blog | Follow On Twitter
    301tool 1.1.5 - URL redirector & shortener (PHP/MySQL)
    Can be hosted on and utilize your own domain

  10. #10
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,358
    Mentioned
    179 Post(s)
    Tagged
    9 Thread(s)
    Quote Originally Posted by paul_wilkins View Post
    It may just be me, but I think that some overthinking may have been occurring here.
    Nah, it's not just you

    Thanks, Paul! Your solution is much better.

  11. #11
    Barefoot on the Moon! silver trophy
    Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,528
    Mentioned
    52 Post(s)
    Tagged
    1 Thread(s)
    I made an additional improvement to the "recreate name/value pair" section. The hidden elements are now created in their own span, which is removed when the dialog is closed. This is so that multiple hidden elements with the same name don't stack up within the form.

    Code:
    $().ready(function(){
        
        var tempFormContainerID= 'temp-form-container';
        
        $('form').submit(function(e){
            
            //if a hidden input named confirmed exists in the form, display yes/no dialog
            if($('form input[name=confirm][type=hidden]').val()){
                e.preventDefault();
                var form = this;
    
                $('<span id="'+tempFormContainerID+'"></span>').hide().appendTo(form);
                
                
              //since the submit button is not passed, recreate the name/value pair as hidden element
                $("button[type=submit], input[type=submit], button", form).eq(0).each(function(){
                    var self = $(this);
                    var tempElement = $('<input type="hidden">');
        
                    //clone the important parts of the button used to submit the form.
                    tempElement
                        .attr("name", this.name)
                        .val(self.val())
                        .appendTo($('#'+tempFormContainerID));
                });
                
                confirmDialog('Confirm', 'Are you sure?', function () {
                    form.submit();
                });
            }
            
        });
        
        function confirmDialog(title, message, success){
            var confirmdialog = $('<div></div>').appendTo('body')
            .html('<div><p>'+message+'</p></div>')
            .dialog({
                modal: true, title: title, zIndex: 10000, autoOpen: false,
                width: 'auto', resizable: false,
                buttons: {
                    Yes: function(){
                        success();
                        $(this).dialog("close");
                    },
                    No: function(){
                        $(this).dialog("close");
                    }
                },
                close: function(event, ui){
                    $('#'+tempFormContainerID).remove();
                    $(this).remove();
                }
            });
            
            confirmdialog.dialog("open");
        }
        
        
    });
    Thanks for the initial suggestion on this approach Paul
    Visit The Blog | Follow On Twitter
    301tool 1.1.5 - URL redirector & shortener (PHP/MySQL)
    Can be hosted on and utilize your own domain


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •