2. 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
3. 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
7. Resolve for Data
Each 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
8. 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.p
arams.tagName);
}]}});
Tuesday, 13 August 13
9. Resolve for Data
Treat your resolved object like a dependency in the controller:
.controller('ViewTagCtrl',
['$scope','$routeParams','tag',
'sparkCluster','log','$location','user','header','sparkClu
stersResolve','tagResolve','currentUserResolve'
Use a ‘route controller’, not a ‘view controller’ (ng-‐controller):
when('/tag/:tagName',
{
controller:
'ViewTagCtrl'
})
Tuesday, 13 August 13
10. Resolve for Rules
Rejected 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
11. 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
12. Resolve for Route-Specific UI
Resolve can pass route-specific configuration to another service
that affects the UI, like “show a promo”.
Using resolve to control UI means:
•Routes handle turning on and off 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
13. when('/tag/:tagName',
{
resolve:
{
makeSparkPromo:
['promo',
function
(promoService)
{
return
promoService.route('makeSparkPromo',
true);
}]}}});
Resolve for Route-Specific UI
Tuesday, 13 August 13
14. 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
16. 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
17. 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
18. 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