user1387219
user1387219

Reputation: 465

Prevent default event and resume afterwards

I want to create an angularjs directive for restricted actions of my web site. For example I have an anchor which would trigger a route change in angular, but before that I want to show a modal login dialog.

I can stop the routing with preventDefault, but I can't resume the routing. I have also tried with dummy event triggering (element.triggerHandler('click')) without success.

I'd like to apply the directive not only to route changing but any other action.

.directive('loginRequired', ['AuthService', 'AUTH_EVENTS',
function(AuthService, AUTH_EVENTS) {
    return {
        link : function(scope, element, attrs) {
            element.on('click', function(e) {
                if (!AuthService.isAuthenticated()) {
                    e.preventDefault();
                    $('#myModal').modal();
                    scope.$on(AUTH_EVENTS.loginSuccess, function() {
                        //resume event
                    });
                    console.log('$scope.$on happened');
                }
            });
        }
    }
}]);

Any suggestion?

Upvotes: 1

Views: 4499

Answers (2)

user1387219
user1387219

Reputation: 465

The solution I found is:

.value('lastPrevented', {
    elem : null
}).directive('loginRequired', ['AuthService', 'lastPrevented',
function(AuthService, lastPrevented) {
    return {
        link : function(scope, element, attrs) {
            element.on('click', function(e) {
                if (!AuthService.isAuthenticated()) {
                    lastPrevented.elem = element;
                    e.preventDefault();
                    $('#myModalLogin').modal();
                }
            });
        }
    }
}]).run(['lastPrevented', '$rootScope', 'AUTH_EVENTS', '$timeout',
function(lastPrevented, $rootScope, AUTH_EVENTS, $timeout) {
    $rootScope.$on(AUTH_EVENTS.loginSuccess, function() {
        $timeout(function() {
            if (!!lastPrevented.elem) {
                lastPrevented.elem[0].click();
                lastPrevented.elem = null;
            }
        })
    });
}]);

That's not resuming... which literally I think is not feasible. The solution is inspired by this question.

Upvotes: 1

Jeff McMahan
Jeff McMahan

Reputation: 1323

I don't think Event.preventDefault() will capture or delay events. AFAIK, it only cancels them outright (see MDN). I don't believe there's a way of resuming the original event with its handler(s) in tact. (But perhaps you don't intend the term 'resume' to be taken quite so literally.)

In this specific case, I think you'll have to examine $(e.target).attr('href'), and later** use it to update the route (you'll need to inject the $location service (Docs) and use its .path() getter/setter method).

-- Best of luck!


**Quick note: you're most likely going to want to pass your 'resume' handlers to your AuthService.isAuthenticated() method, as a callback, as it may wait on some kind of asynchronous business. Rough example:

element.on('click', function(e) {
  e.preventDefault();
  newRoute = $(e.target).attr('href');
  AuthService.isAuthenticated(function () {
    $('#myModal').modal();
    scope.$on(AUTH_EVENTS.loginSuccess, function() {
      $location.path(getWhatYouNeedFromUrlString(newRoute));
    });
  }));
});

You'd setup your .isAuthenticated() method to fire the callback when the user is indeed authenticated.

Upvotes: 0

Related Questions