Marco Prins Marco Prins - 6 months ago 156
Javascript Question

Ember - get target url of transition

I am creating an error hook in my Ember.js app to redirect you to the auth service if you are not allowed to view certain content (in other words, if the server returns a 401).

It looks like this:

Ember.Route = Ember.Route.extend({
error: function(error, transition){
if (error.status === 401) {
window.location.replace("https://auth.censored.co.za");
}
}


Our auth api works as follows: If you send it a parameter called
target
(which is a url), it will redirect you back to that target url after you've logged in.

So I want to somehow get the URL of the route the Ember app was trying to transition to.

Then my code will end up something like this

Ember.Route = Ember.Route.extend({
error: function(error, transition){
if (error.status === 401) {
var target = // Your answer here
window.location.replace("https://auth.censored.co.za?target=" + encodeURIComponent(target));
}
}

Answer

You can get the transition target from the targetName property on the transition object (transition.targetName). And then transitionTo or replaceWith the target from the login route but reloading the app via window.location goes against the point of single page apps.

You are going about this problem in the wrong way, all your routes should be nested under an auth route:

this.route('auth', { path: '/', resetNameSpace: true }, function() {
  // rest of your routes
});

You should be using a service that is injected into all routes to handle authentication, ready made solutions like torii, ember-cli-simple-auth exist to make this easier.

And in the auth route's beforeModel hook you check if the user is authenticated and if not store the transition to be able to retry it when the user logs in:

beforeModel(transition) {
  if (!this.get('session.isAuthenticated')) {
    // keep the transition at hand
    this.controllerFor('login').set('originalTransition', transition);
    // take the user to the login so he can authenticate
    this.transitionTo('login');
  }
}

And from your login route once the user is authenticated and all is good you get the transition that was previously stored and you retry it:

const controller = this.controllerFor('login');
const transition = controller.get('originalTransition');
if (transition) {
  controller.set('originalTransition', null)
  return transition.retry();
}

I am using ES6 syntax, if you are having trouble with it let me know.