Skip to content

Instantly share code, notes, and snippets.

@sebastianseilund
Last active December 17, 2015 23:58
Show Gist options
  • Save sebastianseilund/5692724 to your computer and use it in GitHub Desktop.
Save sebastianseilund/5692724 to your computer and use it in GitHub Desktop.
Sebastian's notes on async router to Alex

Current issues

These are the things that I don't believe is totally consistent and things I think might give problems in different situations. We don't have to solve them all, but make sure that we don't get ourselves into something that's going to be hard to solve.

  • .dispatch (or .perform, .resend or whatever we're gonna call it) needs to be supported in a consistent way.
    • Retrying with previously rejected promises.
    • Should contain the full target route path. It doesn't matter where it came from.
    • Does TransitionEvent replicate itself, or does it have an EventDescriptor that can be reused? Important thing is that we don't reuse the same TransitionEvent instance, as this will mean trouble regarding isAborted and resolved contexts.
    • How do you put extra state on a TransitionEvent that must survive after calling .dispatch? Do you just add properties to it, or should it have a data property that you need to add properties about the transition to (e.g. transitionEvent.data.startTime = new Date().
  • There should only be one activeTransitionEvent on the router. TransitionEvent should have an isAborted boolean property that hooks with multiple async steps can use to check if they should continue or not. When a new transition is started (.transitionTo, {{linkTo}} or .dispatch), the previous one is aborted and the new one becomes the activeTransitionEvent.
  • Consistent return values from router.modelFor. We talked about deprecating router.modelFor, and create a new method on TransitionEvent also called modelFor, that returns the model for a given route name as it would be if/when the transition is finished. If you want the current model you're probably either in a controller, and should use needs, or you can use this.controllerFor('user').get('model'). A model is not active until it's on the controller.
  • What's the point of routeTo? Why don't we just have transitionTo, and it always bubbles an willExit event on all current routes? Then a .dispatch is always simply a new transitionTo called on the current route, no matter where we are at that point.
  • Should calling .perform on TransitionEvent from within a routeTo really stop the bubbling? Why would a child route want to prevent its parent from doing its work?

Thoughts on rejected promises (and a solution?)

I can't think of a good way to support retrying transitions with supplied contexts that are promises. There isn't a generic way to reload the data. Unless...

Let the transitionTo method accept "functions that returns promises" as context. Then every time a TransitionEvent is fired, that function is fired and returns a fresh promise that hasn't been resolved yet. It works kinda like Alex' Lazy Perserverant Promises, but doesn't set any demands for the promises themselves (they can be jqXHR, RSVP.Promise etc.). So, if a developer needs to be able to retry TransitionEvents with promises that can be rejected, he needs to do like this:

App.SomeController = Ember.Controller.extend({
    username: '', //Bound to a textfield in the template
    didClickButton: function() {
        var username = this.get('username');
        this.transitionTo('user', function() {
            return $.get('/users/'+username);
        });
    }
});

Let's say that the AJAX call returns with a 401 Unauthorized status code since the user's session has timed out. Then the jqXHR will be rejected. This will trigger an error (WHERE?). The error handler can then store the TransitionEvent in a transitionToPerformOnceLoggedIn property. Once the user has logged in, we call .perform() on the transitionToPerformOnceLoggedIn, which will once again send the GET request to /users/:username.

In cases where you know that the value has already been resolved, you don't need to incapsulate it in a function. This will work fine in all cases:

App.RepoController = Ember.Controller.extend({
    needs: ['user'],
    goToRepoOwner: function() {
        this.transitionTo('user', this.get('controllers.user.model'));
    }
});

So this is not changing any old functionality. It's just a new option to use, which is necessary for repeated async lookups.

The only unknown I have here is: Who handles the error event? Is it an event that bubbles up from the current route. This probably makes the most sense, since you would probably have an error event handler in your App.ApplicationRoute that checks for 401 requests. Or is it called on the target route? How does it work in the code you've made so far?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment