is it possible to write an interceptor for ng-click? I have a button or a link that leads to a deletion of an object in the backend. I\'d like to have a confirmation dialog
I played with this for a long time, but the async nature of Angular makes it tough to count on every directive playing nicely together. Then, I saw @tosh's answer, which got me thinking.
I think this combines several advantages: Create a Directive and Prepend ngClick
So, just add this directive to your app, and then add the "confirm-click" attribute to your link, as well as the confirmClick() function to your ngClick.
Link:
<a href="#" ng-click="confirmClick() && deleteIt(id)" confirm-click>Delete</a>
Directive:
.directive('confirmClick', function() {
return {
link: function (scope, element, attrs) {
// setup a confirmation action on the scope
scope.confirmClick = function(msg) {
// msg can be passed directly to confirmClick('are you sure?') in ng-click
// or through the confirm-click attribute on the <a confirm-click="Are you sure?"></a>
msg = msg || attrs.confirmClick || 'Are you sure?';
// return true/false to continue/stop the ng-click
return confirm(msg);
}
}
}
})
This is very similar to injecting the standard confirm() dialog, but because you have it in a directive, you can customize how you choose to run your confirm dialog (maybe a pretty modal, instead of a window dialog).
**** BONUS ANSWER ****
I played with this more and integrated a solution that uses a modal window as the confirmation, rather than the default window. Here's the complete solution: https://stackoverflow.com/a/23718694/1135826
I've put an example directive in:
http://plnkr.co/edit/GJwK7ldGa9LY90bMuOfl?p=preview
I achieve it by creating a directive:
priority
than ngClick
, so that it gets called before ngClick
,terminal
so that it doesn't call ngClick
.ngClick
value if the message is ok.As a bonus, you can pass in your own message, such as:
<a href="#" ng-click="deleteIt(id)"
confirmation-needed="Really Delete?"
>Delete with custom message</a>
The code looks like this:
app.directive('confirmationNeeded', function () {
return {
priority: 1,
terminal: true,
link: function (scope, element, attr) {
var msg = attr.confirmationNeeded || "Are you sure?";
var clickAction = attr.ngClick;
element.bind('click',function () {
if ( window.confirm(msg) ) {
scope.$eval(clickAction)
}
});
}
};
});
Hope that helps.
I've given up on getting Piran's answer to work as I'd like it to. Instead, I've started just replacing ngClick with my own directive:
.directive('confirmClick', function() {
return {
restrict: 'A',
link: function(scope, elt, attrs) {
elt.bind('click', function(e) {
var message = attrs.confirmation || "Are you sure you want to do that?";
if (window.confirm(message)) {
var action = attrs.confirmClick;
if (action)
scope.$apply(scope.$eval(action));
}
});
},
};
})
This directive doesn't even have its own scope, which simplifies combining it with other directives significantly. It takes everything it needs directly from the attrs
. It's used like so:
<span ng-show="editing" confirm-click="delete()" confirmation="delete confirmation message goes here">some text</span>
The delete()
function must exist somewhere higher up in the $scope
chain. I'm sure this could be improved by taking a closer look at how ng-click
is implemented, but I haven't gotten around to it yet!
You can inject $window
into your controller so that you can use $window.confirm
from
your scope, then:
<a href="#" ng-click="confirm('message') && deleteIt(id)">Delete</a>