86

I am trying to setup a confirmation dialog on an ng-click using a custom angularjs directive:

app.directive('ngConfirmClick', [
    function(){
        return {
            priority: 1,
            terminal: true,
            link: function (scope, element, attr) {
                var msg = attr.ngConfirmClick || "Are you sure?";
                var clickAction = attr.ngClick;
                element.bind('click',function (event) {
                    if ( window.confirm(msg) ) {
                        scope.$eval(clickAction)
                    }
                });
            }
        };
}])

This works great but unfortunately, expressions inside the tag using my directive are not evaluated:

<button ng-click="sayHi()" ng-confirm-click="Would you like to say hi?">Say hi to {{ name }}</button>

(name is not evaluated is this case). It seems to be due to the terminal parameter of my directive. Do you have any ideas of workaround?

To test my code: http://plnkr.co/edit/EHmRpfwsgSfEFVMgRLgj?p=preview

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
poiuytrez
  • 21,330
  • 35
  • 113
  • 172
  • Why do you use terminal in this case ? It seems that it works perfectly without (and you know it). I just wonder why you think it's necessary in your directive. – Simon Belanger Aug 19 '13 at 12:23
  • @SimonBelanger With terminal = false, even if I click on "cancel" in the confirmation dialog, sayHi() is triggered. My goal is not to call sayHi() if the user clicks on cancel. – poiuytrez Aug 19 '13 at 12:29

17 Answers17

93

If you don't mind not using ng-click, it works OK. You can just rename it to something else and still read the attribute, while avoiding the click handler being triggered twice problem there is at the moment.

http://plnkr.co/edit/YWr6o2?p=preview

I think the problem is terminal instructs other directives not to run. Data-binding with {{ }} is just an alias for the ng-bind directive, which is presumably cancelled by terminal.

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Michael Low
  • 24,276
  • 16
  • 82
  • 119
  • 13
    This code snippet no longer works with the current version of angular. scope.$eval(..) should be replaced with scope.$apply(..) – CoolTapes Jun 09 '14 at 17:07
  • please check this question for a JS confirmation dialog with E2E-tests http://stackoverflow.com/questions/16424961/javascript-confirm-and-angularjs-karma-e2e-test – ndequeker Sep 04 '14 at 12:01
  • This works, but what happens if I check the chrome's checkbox "Avoid this page to create additional dialogs" ? :s – 0x777 Jan 20 '16 at 10:11
58

A clean directive approach.

Update: Old Answer (2014)

It basically intercepts the ng-click event, displays the message contained in the ng-confirm-click="message" directive and asks the user to confirm. If confirm is clicked the normal ng-click executes, if not the script terminates and ng-click is not run.

<!-- index.html -->
<button ng-click="publish()" ng-confirm-click="You are about to overwrite your PUBLISHED content!! Are you SURE you want to publish?">
  Publish
</button>
// /app/directives/ng-confirm-click.js
Directives.directive('ngConfirmClick', [
  function(){
    return {
      priority: -1,
      restrict: 'A',
      link: function(scope, element, attrs){
        element.bind('click', function(e){
          var message = attrs.ngConfirmClick;
          // confirm() requires jQuery
          if(message && !confirm(message)){
            e.stopImmediatePropagation();
            e.preventDefault();
          }
        });
      }
    }
  }
]);

Code credit to Zach Snow: http://zachsnow.com/#!/blog/2013/confirming-ng-click/

Update: New Answer (2016)

1) Changed prefix from 'ng' to 'mw' as the former ('ng') is reserved for native angular directives.

2) Modified directive to pass a function and message instead of intercepting ng-click event.

3) Added default "Are you sure?" message in the case that a custom message is not provided to mw-confirm-click-message="".

<!-- index.html -->
<button mw-confirm-click="publish()" mw-confirm-click-message="You are about to overwrite your PUBLISHED content!! Are you SURE you want to publish?">
  Publish
</button>
// /app/directives/mw-confirm-click.js
"use strict";

var module = angular.module( "myApp" );
module.directive( "mwConfirmClick", [
  function( ) {
    return {
      priority: -1,
      restrict: 'A',
      scope: { confirmFunction: "&mwConfirmClick" },
      link: function( scope, element, attrs ){
        element.bind( 'click', function( e ){
          // message defaults to "Are you sure?"
          var message = attrs.mwConfirmClickMessage ? attrs.mwConfirmClickMessage : "Are you sure?";
          // confirm() requires jQuery
          if( confirm( message ) ) {
            scope.confirmFunction();
          }
        });
      }
    }
  }
]);
mikeborgh
  • 1,192
  • 11
  • 22
47

For me, https://www.w3schools.com/js/js_popup.asp, the default confirmation dialog box of the browser worked a great deal. just tried out this:

$scope.delete = function() {
    if (confirm("sure to delete")) {
        // todo code for deletion
    }
};

Simple.. :)
But I think you can't customize it. It will appear with "Cancel" or "Ok" button.

EDIT:

In case you are using ionic framework, you need to use the ionicPopup dialog as in:

// A confirm dialog


$scope.showConfirm = function() {
   var confirmPopup = $ionicPopup.confirm({
     title: 'Delete',
     template: 'Are you sure you want to delete this item?'
   });

   confirmPopup.then(function(res) {
     if(res) {
       // Code to be executed on pressing ok or positive response
       // Something like remove item from list
     } else {
       // Code to be executed on pressing cancel or negative response
     }
   });
 };

For more details, refer: $ionicPopup

Kailas
  • 7,350
  • 3
  • 47
  • 63
  • It does indeed look clean, however I think it's against the declarative approach in Angular. It's easy to put view logic inside the controller with this approach. If one can, it can be helpful to keep the controller clean from UI elements. – Jim Aho Apr 15 '15 at 11:42
  • 1
    You can get rid of the `== true`, which is completely unnecessary in this case, because `confirm()` already returns a boolean. No need to get JS to type coerce it and compare it to true. – Léo Lam Apr 27 '15 at 10:12
11

Its so simple using core javascript + angular js:

$scope.delete = function(id) 
    { 
       if (confirm("Are you sure?"))
           {
                //do your process of delete using angular js.
           }
   }

If you click OK, then delete operation will take, otherwise not. * id is the parameter, record that you want to delete.

Hendrik
  • 4,849
  • 7
  • 46
  • 51
VBMali
  • 1,360
  • 3
  • 19
  • 46
5

You don't want to use terminal: false since that's what's blocking the processing of inside the button. Instead, in your link clear the attr.ngClick to prevent the default behavior.

http://plnkr.co/edit/EySy8wpeQ02UHGPBAIvg?p=preview

app.directive('ngConfirmClick', [
  function() {
    return {
      priority: 1,
      link: function(scope, element, attr) {
        var msg = attr.ngConfirmClick || "Are you sure?";
        var clickAction = attr.ngClick;
        attr.ngClick = "";
        element.bind('click', function(event) {
          if (window.confirm(msg)) {
            scope.$eval(clickAction)
          }
        });
      }
    };
  }
]);
Stepan Riha
  • 1,736
  • 14
  • 12
  • Works in the version of Angular that you reference in plunker, but if you reference ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js it doesn't work as expected. – ChrisW Mar 25 '14 at 19:04
  • Ultimatelly my suggested approach only work for some cases, because ngClick does way more than simlpy binding to 'click'. I think the more correct approach is to deal with the confirmation in the ng-click handler rather than via a separate attribute. – Stepan Riha Mar 25 '14 at 22:18
4
    $scope.MyUpdateFunction = function () {
        var retVal = confirm("Do you want to save changes?");
        if (retVal == true) {
            $http.put('url', myData).
            success(function (data, status, headers, config) {
                alert('Saved');
            }).error(function (data, status, headers, config) {
                alert('Error while updating');
            });
            return true;
        } else {
            return false;
        }
    }

Code says everything

om471987
  • 5,398
  • 5
  • 32
  • 40
4

In today's date this solution works for me:

/**
 * A generic confirmation for risky actions.
 * Usage: Add attributes: ng-really-message="Are you sure"? ng-really-click="takeAction()" function
 */
angular.module('app').directive('ngReallyClick', [function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('click', function() {
                var message = attrs.ngReallyMessage;
                if (message && confirm(message)) {
                    scope.$apply(attrs.ngReallyClick);
                }
            });
        }
    }
}]);

Credits:https://gist.github.com/asafge/7430497#file-ng-really-js

Nanu
  • 3,010
  • 10
  • 38
  • 52
4

I created a module for this very thing that relies on the Angular-UI $modal service.

https://github.com/Schlogen/angular-confirm

James Kleeh
  • 12,094
  • 5
  • 34
  • 61
4

An angular-only solution that works alongside ng-click is possible by using compile to wrap the ng-click expression.

Directive:

.directive('confirmClick', function ($window) {
  var i = 0;
  return {
    restrict: 'A',
    priority:  1,
    compile: function (tElem, tAttrs) {
      var fn = '$$confirmClick' + i++,
          _ngClick = tAttrs.ngClick;
      tAttrs.ngClick = fn + '($event)';

      return function (scope, elem, attrs) {
        var confirmMsg = attrs.confirmClick || 'Are you sure?';

        scope[fn] = function (event) {
          if($window.confirm(confirmMsg)) {
            scope.$eval(_ngClick, {$event: event});
          }
        };
      };
    }
  };
});

HTML:

<a ng-click="doSomething()" confirm-click="Are you sure you wish to proceed?"></a>
scarlz
  • 2,512
  • 1
  • 17
  • 20
1

HTML 5 Code Sample

<button href="#" ng-click="shoutOut()" confirmation-needed="Do you really want to
shout?">Click!</button>

AngularJs Custom Directive code-sample

var app = angular.module('mobileApp', ['ngGrid']);
app.directive('confirmationNeeded', function () {
    return {
    link: function (scope, element, attr) {
      var msg = attr.confirmationNeeded || "Are you sure?";
      var clickAction = attr.ngClick;
      element.bind('click',function (e) {
        scope.$eval(clickAction) if window.confirm(msg)
        e.stopImmediatePropagation();
        e.preventDefault();
       });
     }
    };
});
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Anil Singh
  • 4,173
  • 4
  • 41
  • 47
1

Confirmation dialog can implemented using AngularJS Material:

$mdDialog opens a dialog over the app to inform users about critical information or require them to make decisions. There are two approaches for setup: a simple promise API and regular object syntax.

Implementation example: Angular Material - Dialogs

Justinas Jakavonis
  • 8,220
  • 10
  • 69
  • 114
0

If you use ui-router, the cancel or accept button replace the url. To prevent this you can return false in each case of the conditional sentence like this:

app.directive('confirmationNeeded', function () {
  return {
    link: function (scope, element, attr) {
      var msg = attr.confirmationNeeded || "Are you sure?";
      var clickAction = attr.confirmedClick;
      element.bind('click',function (event) {
      if ( window.confirm(msg) )
        scope.$eval(clickAction);
      return false;
    });
  }
}; });
Juanma Jurado
  • 574
  • 10
  • 18
0

A very simple angular solution

You can use id with a message or without. Without message the default message will show.

Directive

app.directive('ngConfirmMessage', [function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('click', function (e) {
                var message = attrs.ngConfirmMessage || "Are you sure ?";
                if (!confirm(message)) {
                    e.stopImmediatePropagation();
                }
            });
        }
    }
}]);

Controller

$scope.sayHello = function(){
    alert("hello")
}

HTML

With a message

<span ng-click="sayHello()" ng-confirm-message="Do you want to say Hello ?" >Say Hello!</span>

Without a messsage

<span ng-click="sayHello()" ng-confirm-message>Say Hello!</span>
Merlin
  • 4,907
  • 2
  • 33
  • 51
0

Here is a clean and simple solution using angular promises $q, $window and native .confirm() modal:

angular.module('myApp',[])
  .controller('classicController', ( $q, $window ) => {
    this.deleteStuff = ( id ) => {
      $q.when($window.confirm('Are you sure ?'))
        .then(( confirm ) => {
          if ( confirm ) {
            // delete stuff
          }
        });
    };
  });

Here I'm using controllerAs syntax and ES6 arrow functions but it's also working in plain ol' ES5.

Freezystem
  • 4,494
  • 1
  • 32
  • 35
0

Delete confirmation popup using bootstrap in angularjs

very simple.. I have one solution for this with using bootstrap conformation popup. Here i am provided

<button ng-click="deletepopup($index)">Delete</button>

in bootstrap model popup:

<div class="modal-footer">
  <a href="" data-dismiss="modal" ng-click="deleteData()">Yes</a>
  <a href="" data-dismiss="modal">No</a>
</div>

js

var index=0;
$scope.deleteData=function(){
    $scope.model.contacts.splice(index,1);
}
// delete a row 
$scope.deletepopup = function ($index) {
    index=$index;
    $('#myModal').modal('show');
};

when i click delete button bootstrap delete conformation popup will open and when i click yes button row will deleted.

Rama Krishna
  • 11
  • 1
  • 5
0

ng-click return confirm 100% works

in html file call delete_plot() function

<i class="fa fa-trash delete-plot" ng-click="delete_plot()"></i> 
 
  

Add this to your controller

    $scope.delete_plot = function(){
        check = confirm("Are you sure to delete this plot?")
        if(check){
            console.log("yes, OK pressed")
        }else{
            console.log("No, cancel pressed")

        }
    }
azhar
  • 351
  • 3
  • 13
-1

I wish AngularJS had a built in confirmation dialog. Often, it is nicer to have a customized dialog than using the built in browser one.

I briefly used the twitter bootstrap until it was discontinued with version 6. I looked around for alternatives, but the ones I found were complicated. I decided to try the JQuery UI one.

Here is my sample that I call when I am about to remove something from ng-grid;

    // Define the Dialog and its properties.
    $("<div>Are you sure?</div>").dialog({
        resizable: false,
        modal: true,
        title: "Modal",
        height: 150,
        width: 400,
        buttons: {
            "Yes": function () {
                $(this).dialog('close');
                //proceed with delete...
                /*commented out but left in to show how I am using it in angular
                var index = $scope.myData.indexOf(row.entity);

                $http['delete']('/EPContacts.svc/json/' + $scope.myData[row.rowIndex].RecordID).success(function () { console.log("groovy baby"); });

                $scope.gridOptions.selectItem(index, false);
                $scope.myData.splice(index, 1);
                */
            },
            "No": function () {
                $(this).dialog('close');
                return;
            }
        }
    });

I hope this helps someone. I was pulling my hair out when I needed to upgrade ui-bootstrap-tpls.js but it broke my existing dialog. I came into work this morning, tried a few things and then realized I was over complicating.

Doug Weems
  • 278
  • 2
  • 8