2. ABOUT ME
• Software Engineer at CudaSign formerly SignNow.
(we’re hiring!)
• AngularJS, D3.JS
PHI DONG (@PHIDONG)
3. ROUTER
• ngRoute moved to a module in 1.3
• Router options are now:
• ngRoute
• very simple applications, single view
• UI-Router
• flexible routing, multiple views, nested views,
• ngNewRouter (Component Router)
• new router in development with multiple views, nested views,
and emphasis on easier migration to Angular 2
4. What is ngNewRouter?
• Router for Angular 1.x (1.3+) and Angular 2
developed in TypeScript
• Being maintained by Brian Ford (@briantford)
• Component based, focus on migration path to
Angular 2
• Docs at https://angular.github.io/router/
• Repo at https://github.com/angular/router
• STILL IN DEVELOPMENT (v0.5.3)
8. WAIT.. COMPONENT??
• Angular 1.x:
• template, controller, router (optional)
AppController.$routeConfig([
{
path: '/user',
component: 'user'
}
]);
• Uses “controller as" syntax by default; uses that name to infer
controller name and binds the component name to template
<h1>User Name: {{user.name}}</h1>
user.html
• Changing the name to bind to is in development… (i.e. if you’re
binding to {{vm.foo}} in templates for more reusability)
9. $componentMapperProvider
component: 'myComponent'
WHERE IS ALL THE MAGIC COMING FROM?
• By default serves from ./components so this component would use:
• MyComponentController for controller,
• myComponent for template binding,
• and template get dasherized naming and would load from
./components/my-component/my-component.html
angular.module('app.myComponent', [])
.controller('MyComponentController', [function () {
this.name = 'Friend';
}]);
10. $componentMapperProvider
• We can override this behavior by configuring
$componentMapperProvider using the available methods
$componentMapperProvider#setTemplateMapping
takes a function for mapping component names to component template URLs
$componentMapperProvider#setCtrlNameMapping
takes a function for mapping component names to component controller names
$componentMapperProvider#setCtrlAsMapping
takes a function for mapping component names to controllerAs name in the template
$componentMapperProvider#setComponentFromCtrlMapping
takes a function for mapping component controller names to component names
11. $componentMapperProvider (continued)
• This is done in the configuration step
• For example if we wanted to put our templates in the ./app/components
directory instead of ./components/ and use camel case naming instead of dash
case and bind templates to vm always (i.e. {{vm.name}})
angular.module('app')
.config(componentMappings)
componentMappings = function($componentMapperProvider){
// set custom template mapping
$componentMapperProvider.setTemplateMapping(function(name){
return './app/components/' + name + '/' + name + '.html';
});
// set custom template bindings
$componentMapperProvider.setCtrlAsMapping(function(name){
return 'vm';
});
}
17. OUR :ID PARAMETER AND HOW
TO ACCESS IT
• Can use ng-link to pass parameters
<a ng-link="route2({userId: 33})">View User</a>
• Access in controller using $routeParams
• $routeParams is an object i.e. /route2/33 would be
Object {id: "33"}
angular.module('myApp.component2', []).
controller('Component2Controller', Component2Controller);
function Component2Controller($routeParams) {
this.userId = $routeParams.userId;
}
18. RESOLVES AND THE ROUTER
LIFECYCLE
canActivate
canDeactivate
deactivate
activate
20. HOW CAN I CONTRIBUTE? WHO
CAN I COMPLAIN TO?
• Try it out
• Check existing issues,
uses cases and add
support or new issues/use
cases if they don’t exist
• Help reproduce bugs, fix
bugs and do pull requests
Hey guys. My name is Phi Dong. I’m a software engineer at CudaSign formerly SignNow, an electronic signature company that is part of Barracuda Networks. Today I’m going to be talking about the new angular router that will be released along side 1.4.
don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt don’t say dick butt
So, as you guys know in 1.3 ngRoute was moved into its own module so now when you set up a new Angular project you’ll have a couple of options for routing: ngRoute, UI-Router, and now the ngNewRouter (which is going to be renamed to component router sometime soon).
ngRoute is very simple and only supports one view. UI-router and ngNewRouter both have more flexible routing, multiple views, nested views but ngNewRouter is more focused on an easier migration path to Angular 2.
As you know,newRouter is the new angular router being developed for 1.3 and Angular 2. It is component based and essentially uses the same configuration object which will allow for easier migration to Angular 2 from 1.x.
The docs are available at angular.github.io/router and the repo is under the angular/router
One thing to note is that as of yesterday it’s still pretty raw; it’s in development still and there are many missing apis, features. It’s only 0.5.3 right now and just yesterday there was a commit that changed naming of a bunch of stuff so expect breaking changes going forward.
Alright, so let’s just get into it. We’ll do an npm install angular-new-router and include the router.es5.js distribution file in our index.html and the include ngNewRouter as a dependency in our application.
You’ll notice that there is a new directive ng-outlet. This is similar to ng-view and ui-view. It supports naming like ui-view.
This is all, hopefully, pretty straight forward
Now that we have the dependencies added we can finally start to configure our routes. To do this we’ll use $routeConfig. The route config accepts an array of object pairings that will describe each path. One thing to note here is that while you won’t be using $routeConfig in Angular 2, everything you pass to it, the configuration array, will be the same in Angular 2’s component router.
The path object is pretty straight forward. For example if we have a single view and we want to set up a ‘/user’ route, the pairing is just path: as ‘/user’ string and component as ‘user’. We’ll get more into components later.
(click)
Let’s say we have multiple views though, for example both “main” and a “sideBar”.
(click)
Instead of component with a string we’d have components with an object with our view names as the keys (i.e. main and SideBar) and then the component names as strings.
Now that we have the dependencies added we can finally start to configure our routes. To do this we’ll use $routeConfig. The route config accepts an array of object pairings that will describe each path. One thing to note here is that while you won’t be using $routeConfig in Angular 2, everything you pass to it, the configuration array, will be the same in Angular 2’s component router.
The path object is pretty straight forward. For example if we have a single view and we want to set up a ‘/user’ route, the pairing is just path: as ‘/user’ string and component as ‘user’. We’ll get more into components later.
(click)
Let’s say we have multiple views though, for example both “main” and a “sideBar”.
(click)
Instead of component with a string we’d have components with an object with our view names as the keys (i.e. main and SideBar) and then the component names as strings.
So the configuration looks pretty straight forward. There is just a pair of keys for path and component and not much else. At this point you might have a lot of questions, I know I did. The first of which was what do we mean when we say component? In angular 1 a routable component is made up of a template, controller, and optional router assuming your template has viewports on it.
Let’s go back to our example route configuration. We’ve added the pairing object to our config array now so now we’re pointing to a ‘user’ component. The first thing to note is that this is setting up “controller as” syntax for us by default and the template is automatically bound to the component name. In this case we’d do something like {{user.name}} to bind to the controller’s name property.
So what if you want to bind templates to another name, for example vm? Well… that’s in development. It’s a use case that was brought up and I believe it’s part of the 0.6 milestone..
So some magic is happening with the automatic binding but where is it coming from? Let’s look at $componentLoaderProvider and how it interprets the component value in our route configuration. for a component of ‘myComponent’ it will look for MyComponentController, bind myComponent to the template, and load the template from ./compnents/my-component/my-component.html (dasherized)
But… this isn’t very useful if you have an existing project that you can’t reorganize or a specific style guide you’re following. Luckily this is configurable.
If you guys have looked at newRouter before this might look new but it’s mainly because componentLoaderProvider was renamed to componentMapperProvider yesterday lol
pretend you know what this code does :| also don’
Alright so now we have the confiugration out of the way, let’s compare it to ui-router configuration to newRouter configuration. The “ui well” is pretty similar in both cases. Instead of the ui-view directive there is a router-viewport directive. This directive, like ui-router’s, also accepts naming.
The rest is pretty straight forward although you’re may be wondering where all the extra stuff you configure in UI-Router goes. First off, otherwise…. well, this currently doesn’t exist in NewRouter but it’s part of the 0.6 milestone.
The second thing is resolve. In UI-router you could do a resolve on a state and have that information available to your controller. In NewRouter we’ll actually have to hook into the router lifecycle and do the resolves there.
A quick note though, as I mentioned before, this router is still in development. While making this presentation I found out that even things like the directive names are in flux; this will be changing soon due to some semantics stuff so don’t get too attached to router-viewport.
Links are pretty straight forward. If you’ve used UI-Router this will look very familiar to you. Instead of the ui-sref directive we just use ng-link directive in newrouter.
When we configured we gave the second route the route name “route2” for ui-router but the ng-link goes to the component name for NewRouter. If you wanted to use route2 you could create an alias for it by adding an “as” key to the path object. The ng-link would now point to route 2 instead.
This is especially useful if you have a set of components that you want to create an alias for because you can do an ng-route, in this example, to ‘users’ or ‘userList’ and it’ll go to /route2 but from a dom/template standpoint this can be unclear. Also linking directly to component names will mean reusing components will be more difficult.
Here is an example of the problems you can run into if you don’t set up alias for multi-component items. Say we have 2 routes, route1 and route2. Both have the userList component as the side but route1 has users as the main and route2 has user as the main. So we have aliases on both if we do an ng-link to route2 it’ll go to /route2. If we do an ng-link to the users component it will go to route1 since only route1 has the users component. If we go to the user component it will go to route2 since only route2 has the user component. The tricky part is if we do an ng-link to userList which both routes have it will actually go to route1 since that is first in the configuration array. So to avoid these confusing links it’s best to actually give your route an alias especially if you plan on reusing your components at all.
So, of course, you can also just use a regular href to go to your routes although if you change the path in your configuration later on it won’t automatically update through your app.
So.. what about resolves? We saw before that in UI-router you can resolve in the route configuration. Because new router promotes the concept of components which encapsulate all your component things, we’ll have to do the resolve in the controller. But to do this we have to understand the route’s lifecycle.
The four main lifecycle hooks are canDeactivate, canActivate, deactivate, and activate.
The controller can implement any of these lifecycle hooks to control whether or not navigation is possible.
So when we click on the ng-link to go to our route2, for example, we’ll begin navigation and our component1Controller will check if canReuse evaluates to true. If it’s true it’ll run the reuse method if not it won’t do anything. From here we’ll enter our router lifecycle.
The first thing that will happen is the current controller will check if it’s ok to deactivate this state. This is a good place for logic like checking if you need to prompt a user if they’re sure they want to leave unsaved changes and stuff like that because it happens before the new controller is instantiated.
If it is OK to deactivate it’ll instantiate the new controller. Assuming this succeeds the new controller will do canActivate. So this is where we’d have authentication-type resolves since we only want to deactivate the old controller if the user has aunthentication to proceed.
If this passes it will deactivate the old controller then activate the new one. So activate is where you can run intensive resolves or non-authentication type resolves. If this fails at any point along the way it will cancel navigation otherwise it will complete navigation.
So if you remember when we were comparing UI-router to new router configuration we added a resolve to component2 which wasn’t available in the configuration for new router but we can now add the lifecycle hook to our component2 controller. Since we were just getting the name from a service I’m just going to use the activate lifecycle hook instead of the canActivate since this doesn’t really deal with authentication.
So we do this by adding the activate method to our controller. When the router navigates to this page and enters the activate part of the lifecycle it will run this function and bind name to our view model.
So new router is still in development but you can try it out now. The best way to contribute is probably to let your voice be heard and add support to existing issues/use cases if they pertain to you or submit use cases for things that you use in your application now that aren’t supported by the new router yet. This is important; new router is only at 0.5 right now so if you wait until 1.0 is out to complain about your use case not getting covered it’s partially your fault for not letting people know about it.