I have an angular service for handling modals:
angular.module('myApp').service('ModalService', function($uibModal) {
function open(options) {
return $uibModal.open(options);
}
});
Now I upgraded to angular 1.6 and got this error:
Possibly unhandled rejection: backdrop click
whenever I open a modal and click somewhere else (the backdrop) and the modal closes (as intended). So I want to handle this unhandled exception
in my ModalService
as I do not want to handle this case everytime I use the ModalService
. It is always ok to close the modal via backdrop click, this is no exception.
I tried:
angular.module('myApp').service('ModalService', function($uibModal) {
function open(options) {
var modalInstance = $uibModal.open(options);
modalInstance.result.catch(function error(error) {
if(error === "backdrop click") {
// do nothing
} else {
throw error;
}
})
return modalInstance;
}
});
But this leads to the problem that I cannot handle other errors than backdrop click
as they are always thrown:
ModalService.open({...}).result.catch(function(error) {
// this will catch the error too, but the throw in the ModalService
// will occure in parallel and will not be catched by this function
});
And if I try it like this:
angular.module('myApp').service('ModalService', function($uibModal) {
function open(options) {
var modalInstance = $uibModal.open(options);
modalInstance.result.then(function(whatever) {
return whatever;
}, function rejection(error) {
return error;
});
return modalInstance;
});
});
it resolves the 'unhandled rejection' error, but for every case not just for 'backdrop clicked'.
Has anybody a good solution for this case?
Unfortunately that's how they handle it in The official Plucker for Modal (ui.bootstrap.modal).
If you click on any button it logs something like this:
Modal dismissed at: Thu Feb 23 2017 21:54:26 GMT-0300 (Pacific SA Daylight Time)
What they do is:
modalInstance.result.then(function (selectedItem) {
$ctrl.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
If you remove the error callback, guess what you get:
Possibly unhandled rejection: backdrop click
And even on cancel
Possibly unhandled rejection: cancel
So far, you either do that or use this workaround to silence unhandled rejections
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
use this
$uibModal.open({
////your code......
}).result.then(function(){}, function(res){})
now it will not give you error
UI Specification dependent.
This is NOT the greatest workaround if there are UI specifications that the end-user must be able to click OUTSIDE the modal to close the modal.
If that is NOT the case and there is a little 'x' on the top right of the modal and/or there is a close
backdrop: false, // <<< !!!!!!! (see code below)
will prevent the end-user from clicking OUTSIDE the modal to close the modal.
$scope.change = function (changeableData, p_Mode) {
var modalInstance = $uibModal.open({
templateUrl: whatever,
controller: ModalInstanceCtrl,
scope: $scope,
backdrop: false, // <<< !!!!!!!
resolve: {
// whatever
}
});
This will prevent the error "Possibly unhandled rejection: backdrop click" from occurring.
Once again, you need to look at the UI specifications and/or get permission from the analysts to implement this.
If you're using a controller within your modal. I used this on the closing event. Because 'Closing' is valid but 'Dismissing' is a rejection. This goes within your modal controller, not the parent.
$scope.$on('modal.closing', (event, reason, closed) => {
if (!closed) {
event.preventDefault();
$scope.$close("Closing");
}
});
So your backdrop click will fire the closing event but closed will be passed false. If that's the case, prevent the default behaviour, and programmatically close the modal instead of dismiss. Bare in mind this will break use of dismiss, if you want to use it for its original purpose.