Originally published at: http://www.sitepoint.com/introduction-futuristic-new-router-angularjs/
AngularJS is one of the most popular JavaScript MV* frameworks and is widely used to build single-page applications (SPA). One of the challenging features in SPAs is routing. Routing on the client side involves changing a portion of the view and creating an entry in the browser’s navigation history. As a fully featured client-side framework, AngularJS has always had support for routing via the the ngRoute
module. Although this is good enough for basic routes, it doesn’t support more complex scenarios, such as nested views, parallel views or a sequence of views.
A new router for Angular 2 is currently in progress and it will be back-ported to Angular 1.4. In this article, we will see how the new router can be used to define routes and how it solves some of the problems that ngRoute
couldn’t.
As already stated, work on the new router is still in progress at the time of writing this article and some of the APIs may later change. The Angular team hasn’t thought of a name for the new router yet, so for now it is called the futuristic router.
Limitations of ngRoute
ngRoute
was not created with complex enterprise applications in mind. I have personally seen applications where certain portions of a page need to be loaded in several steps. Such applications can be built using ngRoute
, but it is almost impossible to have a URL state for every single change applied to the view.
The ng-view
directive can be used only once inside an instance of the ng-app
directive. This prevents us from creating parallel routes, as we cannot have two parallel views loading at the same time.
The view template to be rendered inside ng-view
cannot contain another ng-view
directive. This prevents us from creating nested views.
The new router addresses these issues and provides a flexible way of defining and using routes. The new router also embraces the Controller as
syntax . I highly recommend using the Controller as
syntax, as it is one of the conventions to be followed today to get ready for Angular 2.
Creating Simple Routes
The new router is being created with Angular 2 in mind. Angular 2 will simplify dependency injection by eliminating the module config phase, which means that we don’t need to write a config block to define routes—we can define them anywhere.
Every route to be added to the new router consists of two parts:
path
: URL of the route’s templatecomponent
: a combination of a template and a controller. By convention, both controller and template have to be named after the component
Routes are configured with the $router
service . As $router
is a service, we can define the routes anywhere in the app (other than in a provider or, config block). However, we need to make sure that the block of code defining routes is executed as soon as the app is loaded. For example, if the routes are defined in a controller (as we will do shortly), the controller has to be executed on page load. If they are defined in a service, the service method has to be executed in a run block.
Navigating Between Templates
Let’s define two simple routes and navigate between them using the new router. If you want to follow along with this code, you’ll need to grab a copy of the new router. Show me how.
You can install the new router on a per project basis via npm.
mkdir new-router && cd new-router npm install angular-new-router
This will create a folder called node_modules
in your project directory. The new router can be found at node_modules/angular-new-router/dist/router.es5.min.js
. Include it in your project after AngularJS itself.
First off, let’s define a module and configure the routes:
angular.module('simpleRouterDemo', ['ngNewRouter']) .controller('RouteController', ['$router', function($router){ $router.config([ { path:'/', redirectTo:'/first' }, { path:'/first', component:'first' }, { path:'/second/:name', component:'second' } ]); this.name='visitor'; }])
The controller in the above snippet defines three routes. Notice that the root route redirects to our first template and that the third route accepts a parameter in the URL. As you see, the syntax of specifying the parameter is same as it is for ngRoute
.
As already mentioned, every component requires a corresponding view template and a controller. By convention, the name of controller should be name of the component suffixed with “Controller” (so firstController
and secondController
in our case). The name of the view template has to be the same as the name of the component. It also has to reside in a folder with the same name as the component, inside a folder named components
. This would give us:
projectRoot/ components/ first/ first.html second/ second.html
These conventions can be overridden using $componentLoaderProvider
. We will see an example of that later, but for now let’s stick to the conventions.
Next come the views for the components first
and second
used above. We’re defining them in-line using the ng-template
directive (so that we can recreate a runnable demo), but ideally they should be in separate HTML files:
<script type="text/ng-template" id="./components/first/first.html"> <h3>{{first.message}}</h3> </script> <script type="text/ng-template" id="./components/second/second.html"> <h3>{{second.message}}</h3> </script>
As the views are very simple, so are the controllers:
angular.module('simpleRouterDemo') .controller('FirstController', function(){ console.log('FirstController loaded'); this.message = 'This is the first controller! You are in the first view.'; }) .controller('SecondController', function($routeParams){ console.log('SecondController loaded'); this.message = 'Hey ' + $routeParams.name + ', you are now in the second view!'; });
As both of these controllers are created to be used with the Controller as
syntax, they don’t accept $scope
. The $routeParams
service is used to retrieve the values of the parameters passed in the route.
Now, we need to load this controller to have the routes registered:
<body ng-app="simpleRouterDemo" ng-controller="routeController as route"> </body>
Finally, we need to link these routes and load them into the page. The new router brings the ng-link
directive and ng-viewport
directive, which link views and load templates respectively. The ng-viewport
directive is similar to ng-view
; it’s a placeholder for part of your app loaded dynamically based on the route configuration.
The following snippet shows the usage of these directives:
<div class="col-md-3"> <ul class="nav"> <li> <a ng-link="first">First</a> </li> <li> <a ng-link="second({ name:route.name })">Second</a> </li> </ul> </div> <div class="col-md-9"> <ng -viewport></ng> </div>
See the Pen Navigating Between Templates with Angular’s New Router by SitePoint (@SitePoint) on CodePen.
Continue reading this article on SitePoint