Custom "confirm" dialog in JavaScript?

158,360

Solution 1

You might want to consider abstracting it out into a function like this:

function dialog(message, yesCallback, noCallback) {
    $('.title').html(message);
    var dialog = $('#modal_dialog').dialog();

    $('#btnYes').click(function() {
        dialog.dialog('close');
        yesCallback();
    });
    $('#btnNo').click(function() {
        dialog.dialog('close');
        noCallback();
    });
}

You can then use it like this:

dialog('Are you sure you want to do this?',
    function() {
        // Do something
    },
    function() {
        // Do something else
    }
);

Solution 2

SweetAlert

You should take a look at SweetAlert as an option to save some work. It's beautiful from the default state and is highly customizable.

Confirm Example

sweetAlert(
  {
    title: "Are you sure?",
    text: "You will not be able to recover this imaginary file!",
    type: "warning",   
    showCancelButton: true,   
    confirmButtonColor: "#DD6B55",
    confirmButtonText: "Yes, delete it!"
  }, 
  deleteIt()
);

Sample Alert

Solution 3

To enable you to use the confirm box like the normal confirm dialog, I would use Promises which will enable you to await on the result of the outcome and then act on this, rather than having to use callbacks.

This will allow you to follow the same pattern you have in other parts of your code with code such as...

  const confirm = await ui.confirm('Are you sure you want to do this?');

  if(confirm){
    alert('yes clicked');
  } else{
    alert('no clicked');
  }

See codepen for example, or run the snippet below.

https://codepen.io/larnott/pen/rNNQoNp

enter image description here

const ui = {
  confirm: async (message) => createConfirm(message)
}

const createConfirm = (message) => {
  return new Promise((complete, failed)=>{
    $('#confirmMessage').text(message)

    $('#confirmYes').off('click');
    $('#confirmNo').off('click');
    
    $('#confirmYes').on('click', ()=> { $('.confirm').hide(); complete(true); });
    $('#confirmNo').on('click', ()=> { $('.confirm').hide(); complete(false); });
    
    $('.confirm').show();
  });
}
                     
const saveForm = async () => {
  const confirm = await ui.confirm('Are you sure you want to do this?');
  
  if(confirm){
    alert('yes clicked');
  } else{
    alert('no clicked');
  }
}
body {
  margin: 0px;
  font-family: "Arial";
}

.example {
  padding: 20px;
}

input[type=button] {
  padding: 5px 10px;
  margin: 10px 5px;
  border-radius: 5px;
  cursor: pointer;
  background: #ddd;
  border: 1px solid #ccc;
}
input[type=button]:hover {
  background: #ccc;
}

.confirm {
  display: none;
}
.confirm > div:first-of-type {
  position: fixed;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  top: 0px;
  left: 0px;
}
.confirm > div:last-of-type {
  padding: 10px 20px;
  background: white;
  position: absolute;
  width: auto;
  height: auto;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  border-radius: 5px;
  border: 1px solid #333;
}
.confirm > div:last-of-type div:first-of-type {
  min-width: 150px;
  padding: 10px;
}
.confirm > div:last-of-type div:last-of-type {
  text-align: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="example">
  <input type="button" onclick="saveForm()" value="Save" />
</div>

<!-- Hidden confirm markup somewhere at the bottom of page -->

<div class="confirm">
  <div></div>
  <div>
    <div id="confirmMessage"></div>
    <div>
      <input id="confirmYes" type="button" value="Yes" />
      <input id="confirmNo" type="button" value="No" />
    </div>
  </div>
</div>

Solution 4

I would use the example given on jQuery UI's site as a template:

$( "#modal_dialog" ).dialog({
    resizable: false,
    height:140,
    modal: true,
    buttons: {
                "Yes": function() {
                    $( this ).dialog( "close" );
                 },
                 "No": function() {
                    $( this ).dialog( "close" );
                 }
             }
});

Solution 5

var confirmBox = '<div class="modal fade confirm-modal">' +
    '<div class="modal-dialog modal-sm" role="document">' +
    '<div class="modal-content">' +
    '<button type="button" class="close m-4 c-pointer" data-dismiss="modal" aria-label="Close">' +
    '<span aria-hidden="true">&times;</span>' +
    '</button>' +
    '<div class="modal-body pb-5"></div>' +
    '<div class="modal-footer pt-3 pb-3">' +
    '<a href="#" class="btn btn-primary yesBtn btn-sm">OK</a>' +
    '<button type="button" class="btn btn-secondary abortBtn btn-sm" data-dismiss="modal">Abbrechen</button>' +
    '</div>' +
    '</div>' +
    '</div>' +
    '</div>';

var dialog = function(el, text, trueCallback, abortCallback) {

    el.click(function(e) {

        var thisConfirm = $(confirmBox).clone();

        thisConfirm.find('.modal-body').text(text);

        e.preventDefault();
        $('body').append(thisConfirm);
        $(thisConfirm).modal('show');

        if (abortCallback) {
            $(thisConfirm).find('.abortBtn').click(function(e) {
                e.preventDefault();
                abortCallback();
                $(thisConfirm).modal('hide');
            });
        }

        if (trueCallback) {
            $(thisConfirm).find('.yesBtn').click(function(e) {
                e.preventDefault();
                trueCallback();
                $(thisConfirm).modal('hide');
            });
        } else {

            if (el.prop('nodeName') == 'A') {
                $(thisConfirm).find('.yesBtn').attr('href', el.attr('href'));
            }

            if (el.attr('type') == 'submit') {
                $(thisConfirm).find('.yesBtn').click(function(e) {
                    e.preventDefault();
                    el.off().click();
                });
            }
        }

        $(thisConfirm).on('hidden.bs.modal', function(e) {
            $(this).remove();
        });

    });
}

// custom confirm
$(function() {
    $('[data-confirm]').each(function() {
        dialog($(this), $(this).attr('data-confirm'));
    });

    dialog($('#customCallback'), "dialog with custom callback", function() {

        alert("hi there");

    });

});
.test {
  display:block;
  padding: 5p 10px;
  background:orange;
  color:white;
  border-radius:4px;
  margin:0;
  border:0;
  width:150px;
  text-align:center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>


example 1
<a class="test" href="http://example" data-confirm="do you want really leave the website?">leave website</a><br><br>


example 2
<form action="">
<button class="test" type="submit" data-confirm="send form to delete some files?">delete some files</button>
</form><br><br>

example 3
<span class="test"  id="customCallback">with callback</span>
Share:
158,360

Related videos on Youtube

Vivian River
Author by

Vivian River

Updated on July 09, 2022

Comments

  • Vivian River
    Vivian River almost 2 years

    I've been working on an ASP.net project that uses custom 'modal dialogs'. I use scare quotes here because I understand that the 'modal dialog' is simply a div in my html document that is set to appear "on top" of the rest of the document and is not a modal dialog in the true sense of the word.

    In many parts of the web site, I have code that looks like this:

    var warning = 'Are you sure you want to do this?';
    if (confirm(warning)) {
        // Do something
    }
    else {
        // Do something else
    }
    

    This is okay, but it would be nice to make the confirm dialog match the style of the rest of the page.

    However, since it is not a true modal dialog, I think that I need to write something like this: (I use jQuery-UI in this example)

    <div id='modal_dialog'>
        <div class='title'>
        </div>
        <input type='button' value='yes' id='btnYes' />
        <input type='button' value='no' id='btnNo' />
    </div>
    
    <script>
    function DoSomethingDangerous() {
        var warning = 'Are you sure you want to do this?';
        $('.title').html(warning);
        var dialog = $('#modal_dialog').dialog();
        function Yes() {
            dialog.dialog('close');
            // Do something
        }   
        function No() {
            dialog.dialog('close');
            // Do something else
        }    
        $('#btnYes').click(Yes);
        $('#btnNo').click(No);
    }
    

    Is this a good way to accomplish what I want, or is there a better way?

  • Vivian River
    Vivian River over 12 years
    But no matter how I do it, I will have to define custom functions, right? There is no way to be able to write if (confirm('blah?')) like with the built-in confirm function.
  • alnorth29
    alnorth29 over 12 years
    You could basically just spin until the user has clicked on something. The problem with that is that you stop the JS thread from doing anything else while it's waiting. You're probably better off using callback functions.
  • Andrew Brown
    Andrew Brown over 10 years
    what about having your custom confirm function simply return TRUE or FALSE? then handle it by if(customConfirm()){ //do something} else{ //do something else}
  • alnorth29
    alnorth29 over 10 years
    @AndrewBrown But when would the function return? That's the point. You're waiting for the user to click something. To detect that before returning you'd need to keep execution in the body of your function, which you could only do by spinning, and that's a terrible idea.
  • Lokesh Sanapalli
    Lokesh Sanapalli over 7 years
    what is okHandler here, and how to pass it while calling
  • Lokesh Sanapalli
    Lokesh Sanapalli over 7 years
    Got it... it's a function to call when he click on Yes... Thank you... weak in web technologies...
  • Akshay
    Akshay about 7 years
    Hi I tried to use it in my asp.net code but it doesn't trigger the onClick method of the button. Pls help. stackoverflow.com/questions/43227386/…
  • Ramtin
    Ramtin over 5 years
    It would be a good practice to call .off('click') before setting the on click event to make sure that your dialog does not fire multiple events at the same time.
  • Millar248
    Millar248 about 4 years
    This is a great answer. I am still getting used to promises, so this helps me learn that, plus building your own UI is always preferable to using third party libraries.
  • user3284707
    user3284707 about 4 years
    Glad you found it useful :)
  • dmikam
    dmikam over 3 years
    Great trick!!! Really love this solution! Don't really know how this didn't happen to me - looks like pretty logick use of promises. Should be the preferred way for modern browsers.
  • Jake H
    Jake H over 3 years
    For anyone reading this, It's important to do what @Ramtin is suggesting, otherwise each time you click the "yes" button, it will fire multiple events. Of course, I found this out the hard way.
  • Philip
    Philip about 3 years
    This is better than the accepted answer because it doesn't require the use of callbacks
  • Patrick95
    Patrick95 about 2 years
    @alnorth29 I don't understand why I get this error below. I am using dialog() in other parts of application but when I try to use your approach for reusability it breaks. I guess the difference is this time I am trying to use it from a kendoWindow. That is the only difference. Error: TypeError: $(...).dialog is not a function