Kerrick
Kerrick

Reputation: 7478

How to transition to a route from an Ember Data Adapter

In my application, I've got an ApplicationAdapter whose ajaxError method is customized. Within that method, I'd like to be able to transition to a given route. How can I do this?

App.ApplicationAdapter = DS.RESTAdapter.extend({
    ajaxError: function(jqXHR) {
        var error = this._super(jqXHR);
        if (jqXHR) {
            switch(jqXHR.status) {
            // [...]
            case 401:
                // How can I transitionTo('login') here?
            }
            // [...]
        }
    }
});

Upvotes: 3

Views: 1730

Answers (2)

Marcio Junior
Marcio Junior

Reputation: 19128

Instead of transition in the adapter, isn't a good pratice IMHO, you can return an instance of Error and handle it in the error action of the current route:

App.UnauthorizedError // create a custom Error class

App.ApplicationAdapter = DS.RESTAdapter.extend({
    ajaxError: function(jqXHR) {        
        var defaultAjaxError = this._super(jqXHR);
        if (jqXHR) {
            switch(jqXHR.status) {            
                case 401:
                return new App.UnauthorizedError()
            }
        }
        return defaultAjaxError;
    }
});

App.IndexRoute = Ember.Route.extend({
  model: function() {
      return this.store.find('person');
  },
  actions: {
      error: function(reason) {
          // all errors will be propagated to here, we check the instance to handle the UnauthorizedError          
          if (reason instanceof App.UnauthorizedError) {
              this.transitionTo('login')
          }
      }
  }  
});

If you want to use this for all routes, you can put the unauthorized transition in the ApplicationRoute. Because the ApplicationRoute is the parent of all routes, and not handled actions, or actions that return true, will bubble to the parent routes.

App.ApplicationRoute = Ember.Route.extend({
    actions: {
      error: function(reason) {
          if (reason instanceof App.UnauthorizedError) {
              this.transitionTo('login')
          }
      }
  }
});

App.BarRoute = Ember.Route.extend({
    actions: {
        error: function(reason) {
            // handle errors of bar route

            // bubble to application route
            return true;
        }
    }
});

This is a fiddle with this sample http://jsfiddle.net/SkCH5/

Upvotes: 9

Kingpin2k
Kingpin2k

Reputation: 47367

Throw the error and allow the error hook on the route to catch it and transition from there. Additionally you can make a mixin with this logic and add the mixin to all of your routes.

Machty has additional information in his gist talking about the new router: https://gist.github.com/machty/5647589

App.AuthenticatedRoute = Ember.Route.extend({
 beforeModel: function(transition) {
  if (!authTokenPresent) { 
   return RSVP.reject();
   // Could also just throw an error here too...
   // it'll do the same thing as returning a rejecting promise.

   // Note that we could put the redirecting `transitionTo`
   // in here, but it's a better pattern to put this logic
   // into `error` so that errors with resolving the model
   // (say, the server tells us the auth token expired)
   // can also get handled by the same redirect-to-login logic.
  }
 },

 error: function(reason, transition) {
  // This hook will be called for any errors / rejected promises
  // from any of the other hooks or provided transitionTo promises.

  // Redirect to `login` but save the attempted Transition
  var loginController = this.controllerFor('login')
  loginController.set('afterLoginTransition', transition);
  this.transitionTo('login');
 }
});

Upvotes: 0

Related Questions