Angular Modified Bootstrap UI dialog in $ http interceptor hangs browser
I am trying to implement lazy authorization which will only bring up a login dialog when the user makes a call to an API that requires authentication. I am using bootstrap ui.bootstrap.modal (and ui.bootstrap. Warning within modal). The problem is that these directives explicitly state the following teamplateUrl
:
- template / modal / backdrop.html (in
modal.js
here ) - template / modal / window.html (in
modal.js
here ) - template / alert / alert.html (in
alert.js
here )
like this:
.directive('modalBackdrop', ['$timeout', function ($timeout) {
return {
restrict: 'EA',
replace: true,
templateUrl: 'template/modal/backdrop.html',
link: function (scope, element, attrs) {
/* ... */
}
};
}])
And every time I call $modal.open()
and ui-bootstrap creates a DOM for a new modal, angular tries to resolve these urls through the service $http
even if the templates are already loaded either $templateCache.put
or by adding a tag <script>
. This is basically causing infinite recursion in my interceptor trying to enter the login dialog into the request
overload for the URLs above.
Here's a simplified version of my interceptor:
.config(['$provide', '$httpProvider', function($provide, $httpProvider) {
$provide.factory('testInterceptor', ['$injector', function($injector) {
return {
'request': function(config) {
var auth = $injector.get('authService');
var modal = $injector.get('$modal');
if (!auth.LoggedIn) {
var loginModal = modal.open({
template: 'Login screen <alert type="warning">some message</alert>',
});
return loginModal.result;
}
return config;
}
}}]);
Working demo here
Can anyone suggest an approach that doesn't involve hardcoding the templates used in ui.bootstrap.modal
and out ui.bootstrap.alert
?
I also reported this as an issue on github.
source to share
An easy workaround for this is to not force authentication on requests to any URL starting with template/
. For example:
$provide.factory('testIntercepter', ['$q', '$injector',
function($q, $injector) {
return {
'request': function(config) {
if (config.url.indexOf('template/') == 0) {
log('ignoring ' + config.url);
return config;
}
log(config.method + ' ' + config.url);
var auth = $injector.get('authService');
if (!auth.LoggedIn) {
return auth.Login();
}
return config;
},
}
}
]);
Plunker example: http://plnkr.co/edit/kADmHkfHiyKW8kd7aNep?p=preview
A more complicated option might be to check $templateCache
if it contains the requested URL and skip authentication for these cases:
$provide.factory('testIntercepter', ['$q', '$injector', '$templateCache',
function($q, $injector, $templateCache) {
return {
'request': function(config) {
if ($templateCache.get(config.url)) {
log('in $templateCache ' + config.url);
return config;
}
log(config.method + ' ' + config.url);
var auth = $injector.get('authService');
if (!auth.LoggedIn) {
return auth.Login();
}
return config;
},
}
}
]);
Plunker: http://plnkr.co/edit/RfkTmGinobxIWmg1BrMJ?p=preview
source to share
You don't need to use templateUrl
. Check this code (also applies to authorization). I am using inline modal template. This is part of a larger script that opens a modal interface and allows routing in an open modal dialog, so you don't need to close the modal if you want to perform a series of actions in a modal dialog.
$modal.open({
template: "<div data-ng-include='templateUrl'></div>",
controller: function ($scope, $modalInstance) {
$modalInstance.opened
.then(function () {
if (startRouteName != "unauthorized") {
var requiredAuthorizations =
$scope.getRequiredPermissions(startRouteName);
if (requiredAuthorizations) {
$scope.hasAnyPermission(requiredAuthorizations)
.then(function (result) {
if (!result) {
startRouteName = "unauthorized";
}
afterModalOpened($scope);
});
} else {
afterModalOpened($scope);
}
} else {
afterModalOpened($scope);
}
});
}
});
source to share