Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
angular/router
Search
Nikas Praninskas
May 17, 2015
Technology
460
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
angular/router
The New Angular Router
Nikas Praninskas
May 17, 2015
More Decks by Nikas Praninskas
See All by Nikas Praninskas
Static Site Generators with JavaScript
nikaspran
1
370
Move over, Gatsby - React Static in Practice
nikaspran
1
720
Web Components: The (near) Future of Web Development
nikaspran
2
4.1k
Other Decks in Technology
See All in Technology
初海外で注意すべきこと12選!!!安全快適なre:invent生活にするために
yuuuuuuu168
1
190
「エーアイ」をバズワードにしないために RPA 導入経験と Kiro 上での Claude モデル利用経験から
kazzpapa3
0
110
Railsで挑む大量データ永続化 〜600億件を永続化するための設計とボトルネックとの戦い〜
occhi
1
1k
サブエージェントと Claude Mods で作る独自 Advisor ツールの話
kenichiodo
2
180
JAWS-UGグッズ職人仕事の流儀
kentapapa
0
130
Turning Repos into the Product Second Brain with an LLM Wiki
linedevth
0
130
React改造してみた
tsukina_7mochi
0
150
データエンジニアの次の戦場は "プロセスエンジニアリング"
sansantech
PRO
1
140
AIにシークレットを見せない、WSL2で安全な開発環境
yazm
0
330
FinOps Agentが生んだ技術負債:コスト自動調査の落とし穴と解消までの道のり
oasis1994liveforever
3
240
LambdaWebFunctionsを試してみた / exploring-lambda-web-functions
koukihosaka
1
370
AI コーディングと人間の認知スループット / CTO Night & Day 2026 Morning Session / AI Coding and Human Cognitive Throughput
prog893
5
1.4k
Featured
See All Featured
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
450
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.3k
Building the Perfect Custom Keyboard
takai
2
910
Designing for humans not robots
tammielis
254
26k
Evolving SEO for Evolving Search Engines
ryanjones
0
330
KATA
mclloyd
PRO
35
16k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Building a Scalable Design System with Sketch
lauravandoore
464
34k
Marketing to machines
jonoalderson
1
5.9k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Transcript
angular/router The New Angular Router
Hi, I’m Nikas Front end dev @ Wix.com/app-market @nikaspran github/nikaspran
nikas.praninskas.com
The next 45 minutes of your life Prior art What
is the New Angular Router? Migration Current state of affairs
Disclaimer: everything is Work In Progress
Prior art
What ARE frogs Routers?
Deep linking is awesome share information know at a glance
contextualize bookmark The ability to
Don’t break the back button The back button is free
and obvious It is very easy to be annoying if you break navigation
Structure for your app Forces you to modularize Makes apps
easy to understand
ngRoute The default Angular 1 routing solution
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>
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
Simple, but too simple Difficult to do things like modals
sidebars deep routes parallel views complex apps
UI Router The de facto Angular 1 routing solution
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: {...} } }) });
States are intuitive States describe architecture Not everything has to
have a URL Easy to link to parts of your application
Lots of utility <a ui-sref="user.edit({id: 123})"></a> <a href="/base/user/123"></a>
<ui-sref-active> $state.is() $state.go() $state.href() $state.includes() Lots of utility …
Customizability is very important and UI Router does a pretty
good job: christopherthielen/ui-router-extras onEnter, onExit, $stateChange*, ...
…up to a point Do something complex enough and you
start fighting the router
Something complex enough
Same URL, different background state
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
we spent way too much time fighting our tools at
the time, we did a fork still not obvious how to do it all
Angular 2 is coming Can we do better with a
clean slate?
Introducing The New Angular Router
Introducing The New Angular Router
Introducing Component Router
Goals
Be customizable… Let people do complex interesting surprising amazing things
…but have great defaults Make it obvious intuitive quick easy
to learn and use
Multiple views /foo/bar foo bar foo bar parallel nested OR
State-like reverse routing Automatically deep link to components <a router-link="user"
router-params="{id: 123}"></a> <a href="./user/123"></a>
State-like reverse routing Link to multiple components at once sidebar
content mainPage <a router-link="mainPage"></a>
Thought experiment: The router is one of the most important
parts of an application
So… If it is designed for Angular 2
If it is designed for Angular 2 but also works
with Angular 1
If it is designed for Angular 2 but also works
with Angular 1 We have a migration plan! ng1 ng2
Proposed migration scenario ng1 ng1 ng1 ng1 ng1 ng1 Angular
1 app
Proposed migration scenario ng1 ng1 ng1 ng2 ng1 ng1
Proposed migration scenario ng1 ng2 ng1 ng2 ng2 ng1
Proposed migration scenario ng2 ng2 ng2 ng2 ng2 ng2 Angular
2 app
ま よ た ね ぃ み む ょ じ を
り ぉ ね ぼ り ぉ け ば や わ ゎ お ら ゆ ろ り ぉ け ば や わ ゎ お ら ゆ じ ゃ で り ぐ き な ゕ ゟ た ょ を こ で ぷ お じ ぁ だ ど ぬ す っ ら び ぅ ぬ だ ざ ま よ た ね ぃ み む ょ じ を り ぉ ね ぼ び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ひ じ え わ ぶ す ぞ ぷ ゑ っ ぞ ほ だ Show me the code already ま よ た ね ぃ み む ょ じ を り ぉ ね ぼ ろ り ぉ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ お び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ひ じ え わ ぶ す ぞ ぷ ゑ っ ぞ ほ だ ま よ た ね ぃ み む ょ じ を ろ り ぉ け ば や わ ゎ お ら ゆ ほ び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ひ じ え わ ぶ す ぞ ぷ ゑ っ ま よ た ね ぃ み む ょ じ を り ぉ ね ぼ ろ り ぉ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ び ぃ ぅ や こ そ ぶ や あ ゝ ぼ ゆ ぺ み ぶ す ぞ ぷ ゑ っ ぞ ほ だ り ぉ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ お ぉ け ば や わ ゎ お ら ゆ ほ ろ り ぉ け ば や わ ゎ お ら ゆ け ば や わ ゎ お ら ゆ ほ ぞ ぁ ろ り ぉ け ば や わ ゎ お ら ゆ を こ で ぷ お じ ぁ だ ど う え を こ で ぷ お じ ぁ だ ど う え ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぶ す ぞ ぷ ゑ っ ぞ ほ だ ゝ ぼ ゆ ぺ み あ ゝ ぼ ゆ ぺ み あ ゝ ぼ ゆ ぺ み あ ゝ ぼ ゆ ぺ み ぬ す っ ら び ぅ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ だ ざ ぬ す っ ら び ぅ ぬ あ ゝ ぼ ゆ ぺ み ゝ ぼ ゆ ぺ み ま よ た ね び ぃ ぅ や こ そ ぶ ま よ た ね ぃ み
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() { ... }
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() { ... }
Static configuration {path: '/', component: 'list'}, {path: '/edit/:id', component: 'edit'}
{path: '/', component: ListComponent}, {path: '/edit/:id', component: EditComponent} ng2 ng1 === easy to port
Component Router Components Outlets Instructions Pipeline
Component Router Components Outlets Instructions Pipeline
So what’s a component anyway? Template Controller Router
Template - ng2 @View({template: '...'}) @View({templateUrl: '...'})
Template - ng1 $componentMapper .setTemplateMapping(function (compName) { return templatePath; });
./components/my-comp/my-comp.html myComp Uses component convention by default: Customize as you want:
“Controller” - ng2 class MyComp() {...}
Controller - ng1 $componentMapper .setCtrlNameMapping(function (compName) { return controllerName; });
Adds “Controller” by default: Customize as you want: MyCompController myComp
Router Each component can have a child router Child routers
manage their sub-URLs
You can release it as an artifact They can mount
and use it SO,if you build an amazing component with deep linking
Router - ng2 @RouteConfig([ {path: '/', redirectTo: '/main'}, {path: '/main',
component: MainComp}, {path: '/other', components: {}, as: 'other'} ])
Router - ng1 function MainController($router) { $router.config([...]); } function MainController()
{...}; MainController.$routeConfig([...]);
Component Router Components Outlets Instructions Pipeline
Outlet - think ui-view <div ng-outlet></div> <div ng-outlet="left"></div> {path: '/',
components: { default: 'posts', left: 'users' }}
Component Router Components Outlets Instructions Pipeline
Instruction Holds all the context for a transition: Outlets, path,
parameters, ...
Component Router Components Outlets Instructions Pipeline
Pipeline - it’s middleware Takes Instruction Transforms it ..with side
effects $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep
E.g.: pipeline in Angular 1.x $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep
$activateStep Pipeline
Let’s ask the router to go somewhere $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep
$runCanActivateHookStep $loadTemplatesStep $activateStep router.navigate('users/123')
Router generates the instruction $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep
router.navigate('users/123') recognize(): instruction matchedUrl component router children: Instruction[]
Once more unto the pipeline! $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep
$activateStep matchedUrl component router children: Instruction[]
$setupRoutersStep $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep matchedUrl component router
children: Instruction[] Add child instruction routers
$initLocalsStep $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep matchedUrl component router
children: Instruction[] locals Add locals: $router, $routeParams
$runCanDeactivateHookStep $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep matchedUrl component router
children: Instruction[] locals Visit old outlets; run canDeactivate()
$runCanActivateHookStep $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep matchedUrl component router
children: Instruction[] locals Visit new outlets; run canActivate()
$loadTemplatesStep $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep matchedUrl component router
children: Instruction[] locals template Load templates, add to instruction
$activateStep $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep matchedUrl component router
children: Instruction[] locals template Recursively activate outlets (ctrl, tmpl, ...)
Final step… Update $location: http://someHost/base/users/123 … and done!
Pipeline - it’s customizable $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep
Up to you
E.g.: let’s add resolve $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep
resolveStep
Create our step factory .factory('resolveStep', function ($q, $injector) { return
function resolve(instruction) { }; })
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); }); }; })
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); }); }; })
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); }); }; })
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); }); }; })
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); })
End result $setupRoutersStep $initLocalsStep $runCanDeactivateHookStep $runCanActivateHookStep $loadTemplatesStep $activateStep resolveStep Part
of the pipeline Called on every transition
> implications Standardized extension Make it suit your app Publish
and prosper
Component Router Components Outlets Instructions Pipeline Other “stuff”
Sticky components This is how it currently works Under consideration
and desirable
Dynamic loading Add new routes @ runtime: function SomeController($router) {
$router.config([...]); }
Recursive components Not sure how practical, but why not
Migration
ng1 + ngComponentRouter ng2 ng 1.5 + new router Some
things we know
And some we don’t ng1 + X ng1 + ngComponentRouter
ng2 ng 1.5 + new router ?
ngRoute is too simple to worry about
Migration strategies from UI Router are a TODO item But
one can dream…
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
Directives are sort of similar <a router-link="user" router-params="{id: 123}"></a> <a
ui-sref="user({id: 123})"></a> ~== ui-router compRouter
What about what’s missing? Well…
Pipeline! e.g. we saw how to add resolve we can
fake $stateChangeEvents someone write an adapter? :)
How can we prepare? Use similar conventions Component-like architecture Component-like
file structure
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
Current $state of affairs //TODO: draw something totally awesome like
robots and lasers and stuff and maybe a cat
Documentation!
Read the source, Luke: github.com/angular/router
github.com/angular/angular …no wait, now it’s:
but only temporarily…
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)
When? Originally slated for 1.4
…but probably not anymore: :(
June-July? (my somewhat educated guess)
In place of a summary Designed from the ground up;
New ideas for the future; Lessons learned from the past; Not yet ready.
Thank you! nikas.praninskas.com github/nikaspran @nikaspran