Skip to content

Route interceptors in the style of http interceptors #788

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
michalc opened this issue Jan 20, 2014 · 4 comments
Closed

Route interceptors in the style of http interceptors #788

michalc opened this issue Jan 20, 2014 · 4 comments

Comments

@michalc
Copy link

michalc commented Jan 20, 2014

I think it would be useful to be able to add promise-based interceptors for route/stage changes, just like http interceptors. The current setup of using events seems just a little bit limited for anything but simple situations. Use cases:

  • Redirect to a login state if it's known the user isn't logged in for a certain route, and then redirect back, just like you might want to intercept a http request that has failed due to not being logged in on the server.
  • Be able to explain in the current controller (/service) why a particular route change failed, just like how a http request might fail. So something like:
  $state.go('newroute').catch(function(reason) {
    // Show the user the reason
  });
  • Maybe logging of how a user navigates the app? Especially any route change errors.

I feel there are likely others that I haven't thought of.

@nateabele
Copy link
Contributor

I'm not sure I understand what this is adding to the current API. State transitions are already promise-based, and failures already receive an Error object with a reason message.

@michalc
Copy link
Author

michalc commented Jan 20, 2014

Ah... in that case my second example might not be adding anything, if it's already possible.

However, I think my first use-case/point still might be useful. $state.go is promise-based, but then you have an event-based API to configure the different cases of success/error, which (at least appear to be) synchronous in nature, and don't seem to have a built-in way to defer the route change, or to reject it later. So I'm wondering if something like the following could be possible to define:

'stateChangeStart': function(stateChangeDetails) {
  // Say if the user definitely isn't authorised
  return $q.reject('No authorisation');

  // Or maybe show a login form, which still then allows the route change to fail later
  return $modal.show('login');

  // Or even redirect to another route
  return $state.go('newroute');
},
'stageChangeError': function(rejection) {
  // Maybe show global error page?
  return $state.go('error');
}

@jezstephens
Copy link

I agree this would be useful. The use case I have in mind is similar to @michalc's.

I want to configure a listener or interceptor to check whether an "authenticate" flag has been set on the target state. If the flag is set, the interceptor checks whether the user is logged in. If the user is not logged in locally, a request is made to the server. If the server responds with a 401, an $http interceptor displays a login form. Once the user has logged in successfully, the chain of promises is resolved and the target state is entered.

Currently this can be achieved by adding a resolve function to each state requiring authentication, but I think it would be good if this could be made easier and more declarative (e.g. with a flag, as above).

I can't see a way to do this with the events which already exist:

module.run(function($rootScope, auth) {
  $rootScope.$on('$stateChangeStart', function(event, current, previous) {
    if (!current.authenticate) return;
    // auth.getUser() may make a request to the server and returns a promise.
    auth.getUser().then(function() {
      // proceed to "current". (oh, we're already there.)
    }).catch(function() {
      // stay at "previous". (oops, too late...)
    });
  });
});

Alternatively, maybe this can be achieved by adding a "private" resolve function dynamically in a builder decorator if the flag is set? I haven't tried that yet, but it sounds a bit dirty.

@timkindberg
Copy link
Contributor

We are kind of already talking about this over here: #618 (comment).

I'd say this is a dupe. Please read that post (at least from that comment) and then add your thoughts there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants