Slide 1

Slide 1 text

AngularUI Router Why, and What’s Next? ngPittsburgh · Sept 2015

Slide 2

Slide 2 text

Basically a Vanity Slide Former lead dev, CakePHP Founder, Li3 (aka Lithium) Member, AngularUI Team Founding Member / Lead Dev, UI Router Architect, Radify @nateabele [email protected]

Slide 3

Slide 3 text

radify.io · @radify Software Architecture Open Source Strategy · · Training Recruiting &

Slide 4

Slide 4 text

AngularUI What?

Slide 5

Slide 5 text

AngularUI What? AngularUI Router is a state machine that coordinates user interface rendering, data flow, and URL synchronization, as a user navigates through a system.

Slide 6

Slide 6 text

State Machine? “[A] mathematical model of computation used to design both computer programs and sequential logic circuits. It is conceived as an abstract machine that can be in one of a finite number of states.” — Wikipedia: Finite-state machine

Slide 7

Slide 7 text

“The main reason for using state machines is to help the design process. It is much easier to figure out all the possible edge conditions by drawing out the state machine on paper. This will make sure that your application will have less bugs and less undefined behavior.” State Machine?

Slide 8

Slide 8 text

“Moreover, state machines have decades of math and CS research behind them about analyzing them, simplifying them, and much more. Once you realize that in management state machines are called business processes, you'll find a wealth of information and tools at your disposal.” https://www.shopify.com/technology/3383012-why-developers-should-be-force-fed-state-machines State Machine?

Slide 9

Slide 9 text

State Machine? Turnstile

Slide 10

Slide 10 text

State Machine? Light Switch

Slide 11

Slide 11 text

State Machine? Transmission

Slide 12

Slide 12 text

State Machine? E-Commerce System

Slide 13

Slide 13 text

“Make Illegal States Unrepresentable”

Slide 14

Slide 14 text

In the beginning…

Slide 15

Slide 15 text

/users/:id/view /users/:id /users

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Enter Component Router

Slide 19

Slide 19 text

Component Router Nested routes Nested components Navigation pipeline with lifecycle hooks

Slide 20

Slide 20 text

Lifecycle Hooks canActivate activate canDeactivate deactivate

Slide 21

Slide 21 text

Component Router $router.config([ { path: '/', redirectTo: '/home' }, { path: '/home', component: 'home' }, { path: '/users', component: 'users' } ]);

Slide 22

Slide 22 text

Declarative Programming $(document).ready(function() { $('#name').keydown(function(e) { $('h1').html("Hello " + e.target.value) }); });

Hello [Name]!

+

Slide 23

Slide 23 text

Declarative Programming vs.

Slide 24

Slide 24 text

Declarative Programming

Hello {{person.name}}!

Slide 25

Slide 25 text

So what’s new?

Slide 26

Slide 26 text

$rootScope.$on(“$stateChange*”)

Slide 27

Slide 27 text

$rootScope.$on('$stateChangeStart', (e, toState) => { if (toState.data.authorization && !user.isLoggedIn()) { e.preventDefault(); $state.go("login"); } if (toState.data.admin && !user.isAdmin()) { // ... } // ... });

Slide 28

Slide 28 text

$transitionsProvider.onStart({ from: "*" to: “user.*” }, user => user.ensureLogin().then(() => true));

Slide 29

Slide 29 text

$transitionsProvider.onStart({ from: "*" to: “user.*” }, user => user.ensureLogin().then(() => true));

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Hook Values true: transition allowed false: transition rejected { … }: new resolve values Promise<*>: Any value can be promise-wrapped

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

$transitionsProvider.onStart({ to: state => !!state.data.requiresAuth }, (user, $state, $transition$) => { return ( user.isLoggedIn() || $state.redirect($transition$).to('user.login') ); });

Slide 35

Slide 35 text

The Transition Object $transition.to(): the target state $transition.from(): the origin state $transition.params(): target state parameters $transition.options(): passed transition options

Slide 36

Slide 36 text

The Transition Object $transition.entering(): states being entered $transition.exiting(): states being exited $transition.retained(): states retained $transition.views(): view configs for changed states

Slide 37

Slide 37 text

The Transition Object $transition.resolves(): resolve values Planned:

Slide 38

Slide 38 text

Hooks onBefore onStart onFinish onSuccess onError Per Transition onEnter onRetain onExit Per State

Slide 39

Slide 39 text

Types

Slide 40

Slide 40 text

url: "/maps/{location:crazy-regex}"

Slide 41

Slide 41 text

url: "/maps/{location:Location}"

Slide 42

Slide 42 text

export default class Location { constructor( public lat: number, public lon: number, public zoom: number ) {} toString() { return [this.lat, this.lon, this.zoom].join(",") + "z" } }

Slide 43

Slide 43 text

$urlMatcherFactoryProvider.type("Location", { encode(loc) { return “@" + loc; } decode(str) { return new Location( ...str.match(this.pattern).slice(1) ); }, pattern: /@(-?\d+\.\d+),(-?\d+\.\d+),(\d+)z/ });

Slide 44

Slide 44 text

$stateProvider.state("map", { url: "/map/{location:Location}", params: { location: { dynamic: true } } });

Slide 45

Slide 45 text

class MapController { constructor($scope, $stateParams) { // Expose for binding to maps directive $scope.location = $stateParams.location; // Changes to map will auto-propagate to URL $stateParams.$observe("location", () => { ... }) } }

Slide 46

Slide 46 text

Bonus Round TypeScript Trace service Composable builders Resolve policies