In angular2 rc2 with the router module v 3.0.0.6alpha, I extend the RouterOulet to check if the user is logged in before accessing the admin. So this is the code :
@Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet
{
publicRoutes: Array<string>;
private parentOutletMap: RouterOutletMap;
private userService: UserService;
private parentRouter: Router;
constructor(
parentOutletMap: RouterOutletMap,
_location: ViewContainerRef,
@Attribute('name') name: string,
userService: UserService,
parentRouter: Router
) {
super(parentOutletMap, _location, name);
this.parentRouter = parentRouter;
this.parentOutletMap = parentOutletMap;
this.userService = userService;
this.publicRoutes = [
'public',
'login'
];
}
activate(factory: ComponentFactory<any>, activatedRoute: ActivatedRoute, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap)
{
if (this._canActivate(factory.selector)) {
return super.activate(factory, activatedRoute, providers, outletMap);
}
this.parentRouter.navigate(['/login']);
}
_canActivate(url) {
return this.publicRoutes.indexOf(url) !== -1 || this.userService.isLoggedIn()
}
}
userService.isLoggedIn() has to return a boolean. My question is : How do I adapt my code to make an http call to check if the user is logged in ? Because if the isLoggedIn method return an observable object, and I subscribe it, I can't return the result in the parent function.
Please notice that the result of activate method of OutletRouter has changed.
@angular/router-deprecated
activate(nextInstruction: ComponentInstruction) : Promise<any>
@angular/router
activate(factory: ComponentFactory<any>, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap) : ComponentRef<any>
which is not a Promise or Observable any more. New router implementation comes with a bit different solution that I think is cleaner: Guards.
A guard's return value controls the router's behavior:
if it returns true, the navigation process continues if it returns
false, the navigation process stops and the user stays put The guard
can also tell the router to navigate elsewhere, effectively canceling
the current navigation.
The guard might return its boolean answer synchronously. But in many
cases, the guard can't produce an answer synchronously. The guard
could ask the user a question, save changes to the server, or fetch
fresh data. These are all asynchronous operations.
Accordingly, a routing guard can return an Observable and the
router will wait for the observable to resolve to true or `false.
You can create auth.guard.ts:
import { Injectable } from '@angular/core';
import { CanActivate,
Router,
ActivatedRouteSnapshot,
RouterStateSnapshot } from '@angular/router';
import { UserService } from './user.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private userService: UserService, private router: Router) {}
canActivate(
// Not using but worth knowing about
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
) {
return this.userService.isLoggedIn();
}
}
Now make sure your isLoggedIn return Observable (or Promise - try both as Angular2 Reference is not ready yet). In my case API returns JSON in format: { success: true / false }.
public isLoggedIn() : Observable<boolean> | boolean {
let router: Router = this.router;
let obs;
try {
obs = this.authHttp.get('/api/check/logged')
.map(result => result.json())
.map(resultJson => (resultJson && resultJson.success));
} catch (err) {
obs = Observable.of(false);
}
return obs
.map(success => {
// navigate to login page
if (!success)
router.navigate(['/auth/login']);
return success;
});
}
Then just modify your RouterConfig array:
{ path: '/secret', component: SercetComponent, canActivate: [AuthGuard] }
Refer also to Angular2 Developer Guide