Skip to content

Happy New Year

Pre-release
Pre-release
Compare
Choose a tag to compare
@christopherthielen christopherthielen released this 16 Nov 23:04
· 1126 commits to master since this release

After a great deal of thought, hard work, and a lot of feedback and support from the community, the AngularUI Router team is proud to announce the first alpha release of UI Router 1.0. It is the culmination of a complete rewrite of the internal architecture of the 0.2.x series (as well as a port to TypeScript), which began over 18 months ago, and has resulted in a more robust, more flexible design, which addresses many of our community’s biggest requests and most pressing concerns.

Backwards Compatibility

Despite the massive refactor, we've managed to retain almost 100% API compatibility with 0.2.x, barring a few small semantic differences:

  • Return values for onEnter/onExit hooks are now meaningful (see below), so if you're using CoffeeScript or defining hooks with ES6 arrow functions, add && null to your return expression if you don't want to opt in to any new behavior
  • To ease debugging for new users, certain errors that would otherwise be swallowed (i.e. in resolves) are now printed to the console by default; this can be disabled with $transitionsProvider.defaultErrorHandler(() => {}) (see more about the new $transitions service below)
  • Due to the design of the new view system, templates are required for all views
  • All state events, (i.e. $stateChange* and friends) are deprecated and disabled by default; re-enable them by including the ng1/stateEvents.js file, and depend on the ui.router.state.events angular module in your application.

New Features

The refactor has also enabled a number of important new features:

Transition hooks

http://angular-ui.github.io/ui-router/feature-1.0/interfaces/transition.ihookregistry.html

Internally, the state transition system is now implemented as a highly-configurable pipeline of operations and dependent relationships. This pipeline exposes a number of hook points that provide much more flexibility over the previous event-driven architecture.

The hooks system interface allows application code to be much more targeted around specific groups or types of transitions. Hooks have also been made more expressive by allowing meaningful return values. For example, this hook disables all transitions from children of foo states to children of bar states:

$transitionsProvider.onStart({ from: 'foo.*', to: 'bar.*' }, () => false);

Matching rules allow specific states to be targeted, and can target based on glob rules, as with $state.includes(). Matching rules can also be functions, enabling patterns like the following:

$transitionsProvider.onStart({
  to: (state) => !!state.data.requiresAuth
}, (UserService) => UserService.current().then(() => true, () => false));

Some things to note:

  • The matching rule returns the boolean value of requiresAuth in the state's custom data to determine whether to enforce a current user session
  • The paired hook function is injectable, meaning it can accept any custom services, as well as some special injectable values (see below)
  • This hook function returns a promise, which will hold the transition until the promise resolves, meaning you can use this pattern for implementing flows such as prompting for auth information, then resuming the transition
  • Finally, the promise returns a boolean value; returning false from a hook (either through a promise or directly) will cancel the transition

The Transition pipeline has first-class support for redirecting transitions. Simply return a TargetState from a hook using the $state.target() factory method.

Consult the 1.0 hook documentation for the full list of hooks and where they take place within the transition pipeline.

State-specific hooks

In addition to transition-level hooks (which are equivalent in scope to $stateChange* events), $transitionsProvider also implements state-specific hooks, which are essentially global versions of the standard onEnter/onExit hooks. These fire once per state being entered or exited, and provide a $state$ injectable, representing the state object being entered or exited. These hooks allow you to implement common enter/exit logic across groups of states.

We've also introduced a new hook, onRetain, which allows you to define how a state should behave when it is held over during a transition.

The Transition Object

http://angular-ui.github.io/ui-router/feature-1.0/classes/transition.transition-1.html

Instead of an endless list of parameters as in the state events of 0.2.x, all transition details are now fully encapsulated in the Transition object. You can inspect parameters, origin and destination states, resolves, and trace back transition redirections.

The Transition object allows you to add or override resolves at runtime using the addResolves() method, the Transition object exposes the same set of hooks as $transitionsProvider, such that hooks (e.g., onFinish()) can be applied on a per-transition basis.

The Transition object is available as an injectable in any hook as $transition$.

Resolve Policies

We've made it possible to tune exactly how resolves are handled, with the following options available:

  • EAGER: All eager resolves for a transition are resolved at the beginning, before any states are entered (this is way UI-Router 0.2.x handles resolves)
  • LAZY: Lazy resolves are resolved when the state they are declared on is entered.
  • JIT: Just-In-Time resolves do not resolve until just before they are injected into some other function. (extremely lazy)

In the future, this will enable powerful progressive rendering capabilities.

Sample App, State Visualizer, Transition Visualizer

We're working on a new sample app (Source), as well as a state and transition visualizer. Check them out, and give us some feedback. We'd like to make the visualizers into a Chrome Extension that you can enable on any UI-Router 1.0 app.

Why UI Router?

With the advent of Angular 2 and the Component Router, we’re often asked if UI Router still has a place in the Angular ecosystem. From what we’ve observed, we believe that the answer to that question is an unequivocal yes. While Component Router offers a number of advancements in DOM handling and lifecycle management, it still couples routes 1:1 with components.

We believe that for sophisticated applications (and even not-so-sophisticated ones), a hierarchical state machine is the best abstraction boundary, allowing application code to stay declarative, and well organized. This, among many other reasons (like typed and dynamic parameters), is why we've been hearing over and over again from enterprise users to solo developers, that UI Router support is at or near the top of their needs list for migrating their applications to Angular 2.

The Future

Our immediate goal is to collect feedback on this release so that we can make sure we're not missing any important use cases or breaking compatibility in any unintended way. To do that, we need your help. Please test UI Router against your app, and let us know if you experience any issues. Try out the new features and let us know if there's anything (not already on the roadmap) that we're still missing.

After we've shipped the final 1.0 release, we're heading back into the workshop with the following priorities:

  • Angular 2 Support: Unsurprisingly, this has been our most oft-request feature of late, and by converting the codebase to TypeScript, we're already a long way towards supporting it; our goal is to support Angular 1 and 2 simultaneously, and provide people who wish to stay with UI Router a smooth (as possible) transition path
  • Pipeline API: We plan to further decouple the internal transition pipeline at the core of UI Router, and implement a public API for managing it — this will enable even more sophisticated UI state handling, such as parallel transitions and multiple active states (see: 'sticky states' from UI Router Extras)
  • Lazy Loading & Runtime State Tree Management: Load, add, move, and remove states and state hierarchies on the fly
  • Progressive Rendering: An important mobile-first feature, it will allow much finer tuning of the user experience while waiting for dependency data to resolve
  • Documentation: We've switched to TypeDoc, for documentation generation. We still have a lot of work to do to get the documentation quality back up to our standards; bear with us.

Resources

  • ngPittsburgh, Sept 2015: A talk that explains UI Router's philosophy, differences from Component Router, and new features in 1.0

Acknowledgements

  • First and foremost, I'd like to thank my co-conspirator, Chris Thielen, especially for being longsuffering with my perfectionism
  • Wesley Cho, for kick-starting the port to TypeScript, crushing some pretty difficult bugs, and generally being a great source of intel and encouragement
  • Rob Wormald, for architectural inspiration, patience for our never-ending streams of questions, and general cleverness