Angular JS Routing
Post on 03-Jul-2015
4818 Views
Preview:
DESCRIPTION
Transcript
AngularJS Application Routing
Tuesday, 13 August 13
Routes: REST/Servers v. Client Apps
•HTTP is stateless, so routes help define application state. •REST emphasizes semantic routes. (GET /user/dave)
But...•There is more state than can be represented in a route (user state, session state)•Client-side apps don’t actually need routes to work (e.g. many jquery-based apps)
Tuesday, 13 August 13
Why use routes?
Routes:• Make the back button work as expected• Make major (page-like) transitions clear• Allow easy linking• Make testing easier• Encapsulate some state
Tuesday, 13 August 13
From Angular-Phonecat:
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']). config(['$routeProvider', function($routeProvider) { $routeProvider.
when('/phones', {templateUrl: 'partials/phone-‐list.html', controller: PhoneListCtrl}).
when('/phones/:phoneId', {templateUrl: 'partials/phone-‐detail.html', controller: PhoneDetailCtrl}).
otherwise({redirectTo: '/phones'});}]);
Basic Routes
Tuesday, 13 August 13
.when('/phones/:phoneId', {templateUrl: 'partials/phone-‐detail.html', controller: PhoneDetailCtrl})
:phoneId stored in $route.current.params, available controller and resolve functions.
Basic Routes
Tuesday, 13 August 13
Realistic Routes Structure/ – welcome/stream – logged-in home/login – log-in/signup – signup/user/:username – user profile /explore – explore tags/settings – user settings/new-spark – create spark page/spark/cluster?sparkName=&tagName – spark cluster page/search – search/spark/:username/:slug – spark page...and 11 more routes
Tuesday, 13 August 13
Resolve for DataEach item in the resolve map:
•Runs before the controller is instantiated•Provides its value to the controller•If it is a promise:
•It will (wait to) resolve the promise first•If the promise is rejected, the route errors
Using resolve for database objects means•No UI flicker as promises are resolved•Controllers can assume objects exist•Tests are cleaner: pass in data object explicitly
Tuesday, 13 August 13
Resolve for Data
when('/tag/:tagName', { resolve: { tagResolve: ['tag','$route', function (tagService, $route) { return tagService.get($route.current.params.tagName); }], sparkClustersResolve: ['sparkCluster','$route', function (sparkClusterService, $route) { return sparkClusterService.getSparkClustersByTag($route.current.params.tagName);}]}});
Tuesday, 13 August 13
Resolve for Data
Treat your resolved object like a dependency in the controller:.controller('ViewTagCtrl', ['$scope','$routeParams','tag','sparkCluster','log','$location','user','header','sparkClustersResolve','tagResolve','currentUserResolve'
Use a ‘route controller’, not a ‘view controller’ (ng-‐controller):when('/tag/:tagName', { controller: 'ViewTagCtrl' })
Tuesday, 13 August 13
Resolve for RulesRejected Promises cause routes to fail. You can use this to make rules for the route like ACLs or prerequisites. Reject a promise to cause a route to fail.
Using resolve to make rules means:•All resolution rules must pass before route succeeds and controller is instantiated. •Common ACLs (logged-in) specified in routes, not each controller or service•Can redirect the user to an appropriate page (also can do user-facing error)
Tuesday, 13 August 13
when('/tag/:tagName', { resolve: { mustAuth : ['route', function (routeService) { return routeService.mustAuth('/');}]}]}});
routeService.mustAuth = function (redirectTo) { var authDeferred, p; authDeferred = $q.defer(); p = userService.getCurrent(); p.then(function (currentUser) { if (angular.isUndefined(currentUser._id)) { $location.url(redirectTo); authDeferred.reject(); } else { authDeferred.resolve(mustAuth); }}); return authDeferred.promise;};
Resolve for Rules
Tuesday, 13 August 13
Resolve for Route-Specific UI
Resolve can pass route-specific configuration to another service that a"ects the UI, like “show a promo”.
Using resolve to control UI means:•Routes handle turning on and o" UI elements•Route Controllers don’t need to worry about configuring site-wide UI elements like headers, promos, menus
*There are other (possibly better) options for this, including having the UI controller listen to RouteChangeSuccess events.
Tuesday, 13 August 13
when('/tag/:tagName', { resolve: { makeSparkPromo: ['promo', function (promoService) { return promoService.route('makeSparkPromo', true);}]}}});
Resolve for Route-Specific UI
Tuesday, 13 August 13
Testing Routes Midway
Normally you can only test routing with E2E testing, slowly.
Midway Testing (see Year Of Moo) is basically big unit testing.
Use a router helper, which has routeDefined, getRoute.
Midway testing routes means unittesting-like speed and E2E-like app setup.
Tuesday, 13 August 13
ROUTER.when('tag', '/tag/:tagName', { templateUrl: '/partials/tag/tag-‐detail.html', controller: 'ViewTagCtrl'});
ROUTER.otherwise({ redirectTo : '/'});
ROUTER.install($routeProvider);
Testing Routes Midway–Router Helper
Tuesday, 13 August 13
before(function(done) { test = new ngMidwayTester(); test.register('App', done);});
it('should have a route to a tag page', function() { expect( ROUTER.routeDefined('tags')).to.equal(true); var url = ROUTER.routePath('tags', {tagName: ‘cooking’); expect(url).to.equal('/tag/cooking');});
Testing Routes Midway–Testing
Tuesday, 13 August 13
Recap
The phonecat way (sticking everything under app) is unscalable.
Angular’s route system is flexible and powerful, if you take advantage of resolve and promises.
Using helper functions and midway testing means you can unit test more things. The less you rely on E2E testing, the better.
Tuesday, 13 August 13
Other Good Ideas
Others have addressed the same problems in a more reusable way.
Angular UI router: use ‘state’ instead of routes. Seems good. Worth considering if you start fresh.
Angular App: great example of well-designed app, but maybe hard to follow for a novice. Interesting crudRouteProvider implementation.
Tuesday, 13 August 13
top related