3

I'm trying to implement lazy authorization which will bring in the login dialog only when user triggers call to API requiring authentication. I'm using bootstrap ui.bootstrap.modal (and ui.bootstrap.alert within the modal). The problem is that these directives explicitly specify following teamplateUrl's:

  • 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'm calling $modal.open() and ui-bootstrap builds DOM for new modal window, angular tries to resolve those urls via $http service even though the templates are already loaded either by $templateCache.put method or by adding a <script> tag. This is basically causing infinite recursion in my interceptor which tries to bring in login dialog in request overload for the urls above.

Here is 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 is here

Can anyone advise the approach which will not involve hard-coding of the templateUrls used in ui.bootstrap.modal and ui.bootstrap.alert?

I've also reported this as an issue on github.

2
  • How come you're using $injector instead of just passing those things in as dependencies? i.e. $injector.get('$modal') Commented Nov 13, 2014 at 22:04
  • this won't work supposedly because interceptor is being registered in config section which supports only providers injection (see documentation) Commented Nov 18, 2014 at 21:09

2 Answers 2

5

A simple way to workaround this is to not enforce authentication on requests to any URL that begins with template/. Like so:

      $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;
            },
          }
        }
      ]);

Example Plunker: http://plnkr.co/edit/kADmHkfHiyKW8kd7aNep?p=preview


A more sophisticated option might be to check the $templateCache if it contains the URL requested, and skip authentication for those 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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @sirhc, I would do both checks. Good point about $templateCache!
0

You don't have to use templateUrl. Check this code out (also deals with authorization). I use inline modal template. This is part of bigger script that opens modal and allows routing within open modal dialog, so that one does not have to close modal when you want to perform 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);
             }
         });
     }
});

1 Comment

I'm also using inline template in my example the problem is that angular-ui itself is using templateUrl, which causes my itercepter to loop

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.