Upgrade to Pro — share decks privately, control downloads, hide ads and more …

angular/router

 angular/router

The New Angular Router

Nikas Praninskas

May 17, 2015
Tweet

More Decks by Nikas Praninskas

Other Decks in Technology

Transcript

  1. The next 45 minutes of your life Prior art What

    is the New Angular Router? Migration Current state of affairs
  2. Deep linking is awesome share information know at a glance

    contextualize bookmark The ability to
  3. Don’t break the back button The back button is free

    and obvious It is very easy to be annoying if you break navigation
  4. ngRoute - very simple .config(function($routeProvider){ $routeProvider .when('/user/:id', { templateUrl: 'user.html',

    controller: 'UserCtrl', resolve: {...} }) .when('/user/:id/edit', { templateUrl: 'userEdit.html', controller: 'UserEditCtrl' }); }); One view per app One URL, one view <a href="user/123"></a> <a href="user/123/edit"></a> <div ng-view></div>
  5. Good things come to those who wait .when('/user/:id', { ...,

    resolve: { user: function($q) { var data = $q.defer(); //get user data from API return data.promise; } } }) Inject into controller from configuration Waits until promises resolve
  6. Simple, but too simple Difficult to do things like modals

    sidebars deep routes parallel views complex apps
  7. UI Router - much more powerful <a ui-sref="layout.user"></a> <a ui-sref="layout.user.edit(

    {id: 123})"></a> <div ui-view="sidebar"></div> <div ui-view="content"></div> State based routing .config(function($stateProvider){ $stateProvider .state('layout', { abstract: true, templateUrl: 'layout.html' }) .state('layout.user', { views: { sidebar: { templateUrl: 'sidebar.html', controller: 'SidebarCtrl', resolve: {...} }, content: {...} } }) });
  8. States are intuitive States describe architecture Not everything has to

    have a URL Easy to link to parts of your application
  9. Customizability is very important and UI Router does a pretty

    good job: christopherthielen/ui-router-extras onEnter, onExit, $stateChange*, ...
  10. Multiple paths that preserve history 1. Open App Market 2.

    Click App icon Use direct link to App (eg. via social) wix.com/app-market/:appName/overview
  11. we spent way too much time fighting our tools at

    the time, we did a fork still not obvious how to do it all
  12. State-like reverse routing Automatically deep link to components <a router-link="user"

    router-params="{id: 123}"></a> <a href="./user/123"></a>
  13. State-like reverse routing Link to multiple components at once sidebar

    content mainPage <a router-link="mainPage"></a>
  14. If it is designed for Angular 2 but also works

    with Angular 1 We have a migration plan! ng1 ng2
  15. ま よ た ね ぃ み む ょ じ を

    り ぉ ね ぼ り ぉ け ば や わ ゎ お ら ゆ ろ り ぉ け ば や わ ゎ お ら ゆ じ ゃ で り ぐ き な ゕ ゟ た ょ を こ で ぷ お じ ぁ だ ど ぬ す っ ら び ぅ ぬ だ ざ ま よ た ね ぃ み む ょ じ を り ぉ ね ぼ び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ひ じ え わ ぶ す ぞ ぷ ゑ っ ぞ ほ だ Show me the code already ま よ た ね ぃ み む ょ じ を り ぉ ね ぼ ろ り ぉ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ お び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ひ じ え わ ぶ す ぞ ぷ ゑ っ ぞ ほ だ ま よ た ね ぃ み む ょ じ を ろ り ぉ け ば や わ ゎ お ら ゆ ほ び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ひ じ え わ ぶ す ぞ ぷ ゑ っ ま よ た ね ぃ み む ょ じ を り ぉ ね ぼ ろ り ぉ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ぶ す ぞ ぷ ゑ っ ぞ ほ だ り ぉ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ お ぉ け ば や わ ゎ お ら ゆ ほ ろ り ぉ け ば や わ ゎ お ら ゆ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ お ら ゆ を こ で ぷ お じ ぁ だ ど う え を こ で ぷ お じ ぁ だ ど う え ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぶ す ぞ ぷ ゑ っ ぞ ほ だ ゝ ぼ ゆ ぺ み あ ゝ ぼ ゆ ぺ み あ ゝ ぼ ゆ ぺ み あ ゝ ぼ ゆ ぺ み ぬ す っ ら び ぅ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ あ ゝ ぼ ゆ ぺ み ゝ ぼ ゆ ぺ み ま よ た ね び ぃ ぅ や こ そ ぶ ま よ た ね ぃ み
  16. Angular 2.x import {ListComponent} from './list'; import {EditComponent} from './edit';

    @Component({...}) @View({template: '...'}) @RouteConfig([ {path: '/', component: ListComponent}, {path: '/edit/:id', component: EditComponent} ]) class AppComponent() { ... }
  17. Angular 1.x $componentMapper .setCtrlNameMapping(comp => comp + 'Ctrl'); $componentMapper .setTemplateMapping(comp

    => comp + '.html'); AppController.$routeConfig([ {path: '/', component: 'list'}, {path: '/edit/:id', component: 'edit'} ]); function AppController() { ... }
  18. Static configuration {path: '/', component: 'list'}, {path: '/edit/:id', component: 'edit'}

    {path: '/', component: ListComponent}, {path: '/edit/:id', component: EditComponent} ng2 ng1 === easy to port
  19. Template - ng1 $componentMapper .setTemplateMapping(function (compName) { return templatePath; });

    ./components/my-comp/my-comp.html myComp Uses component convention by default: Customize as you want:
  20. Controller - ng1 $componentMapper .setCtrlNameMapping(function (compName) { return controllerName; });

    Adds “Controller” by default: Customize as you want: MyCompController myComp
  21. You can release it as an artifact They can mount

    and use it SO,if you build an amazing component with deep linking
  22. Router - ng2 @RouteConfig([ {path: '/', redirectTo: '/main'}, {path: '/main',

    component: MainComp}, {path: '/other', components: {}, as: 'other'} ])
  23. Pipeline - it’s middleware Takes Instruction Transforms it ..with side

    effects $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep
  24. Let’s ask the router to go somewhere $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep

    $runCanActivateHookStep $loadTemplatesStep $activateStep router.navigate('users/123')
  25. Router generates the instruction $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep

    router.navigate('users/123') recognize(): instruction matchedUrl component router children: Instruction[]
  26. Recurse over instructions .factory('resolveStep', function ($q, $injector) { return function

    resolve(instruction) { var promises = []; return instruction.router.traverseInstruction( instruction, queueResolves ).then(function () { return $q.all(promises); }); }; })
  27. Get config from instruction .factory('resolveStep', function ($q, $injector) { return

    function resolve(instruction) { var promises = []; function queueResolves(instruction) { var cfg = getResolveConfigFrom(instruction); } return instruction.router.traverseInstruction( instruction, queueResolves ).then(function () { return $q.all(promises); }); }; })
  28. Queue the resolution .factory('resolveStep', function ($q, $injector) { return function

    resolve(instruction) { var promises = []; function queueResolves(instruction) { var cfg = getResolveConfigFrom(instruction); var resolve = $q.when($injector.invoke(cfg.value)); promises.push(resolve.then(function (resolved) { })); } return instruction.router.traverseInstruction( instruction, queueResolves ).then(function () { return $q.all(promises); }); }; })
  29. Add it to locals .factory('resolveStep', function ($q, $injector) { return

    function resolve(instruction) { var promises = []; function queueResolves(instruction) { var cfg = getResolveConfigFrom(instruction); var resolve = $q.when($injector.invoke(cfg.value)); promises.push(resolve.then(function (resolved) { instruction.locals[cfg.key] = resolved; })); } return instruction.router.traverseInstruction( instruction, queueResolves ).then(function () { return $q.all(promises); }); }; })
  30. Insert it into the pipeline .config(function ($pipelineProvider) { var steps

    = $pipelineProvider.steps; var atPosition = steps.indexOf('$runCanDeactivateHookStep) + 1; //insert resolveStep after $runCanDeactivateHookStep steps.splice(atPosition, 0, 'resolveStep'); $pipelineProvider.config(steps); })
  31. Multi-components are sort of like states $router.config([{ as: 'category', path:

    '/:category', components: { sidebar: 'Sidebar', content: 'Category' } }]); $stateProvider .state('category', { url: '/:category', views: { sidebar: { templateUrl: '...', controller: '...' }, content: { templateUrl: '...', controller: '...' } } }); ui-router compRouter
  32. Directives are sort of similar <a router-link="user" router-params="{id: 123}"></a> <a

    ui-sref="user({id: 123})"></a> ~== ui-router compRouter
  33. Pipeline! e.g. we saw how to add resolve we can

    fake $stateChangeEvents someone write an adapter? :)
  34. Write unit tests UI Router configuration is testable Write now,

    then verify migration later http://nikas.praninskas.com/test-ui-router Component Router should be even easier
  35. Current $state of affairs //TODO: draw something totally awesome like

    robots and lasers and stuff and maybe a cat
  36. Codebase is a bit of a mess: 1.x has not

    worked for over a month everything in ng2 repo until build is stable still working out core issues (i.e. reverse routing)
  37. In place of a summary Designed from the ground up;

    New ideas for the future; Lessons learned from the past; Not yet ready.