Reputation: 5903
I'm trying to load the home page of my app for visitors who are not authenticated.
const routes: Routes = [
{ path: '', loadChildren: './home/home.module#HomeModule' }
...
Authenticated users should get their feed via that module, also on the empty path.
{ path: '', loadChildren: './feed/feed.module#FeedModule', canActivate: [IsAuthenticationGuard] },
{ path: '', loadChildren: './home/home.module#HomeModule', canActivate: [NoAuthenticationGuard] },
I would expect that IsAuthenticationGuard
would fail and load the default home component.
Instead it DOES download the feed module package (shown in the network tab) but loads nothing in the router outlet. Very confusing.
How can I do conditional routing (based on guards or otherwise) on the empty path?
Update: Here are the guards by request
@Injectable()
export class IsAuthenticationGuard implements CanActivate {
constructor(
private authenticationService: AuthenticationService
) { }
public canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
return this.authenticationService.isAuthenticated.pipe(take(1), map((isAuthentication) => {
return isAuthentication;
}));
}
}
I've researched the new urlTree
and it's cool that you can now redirect via the route instead of within the guard. However, redirects don't seem applicable if you're trying to use the same route with a different module. Plz correct me if there is a way.
Upvotes: 11
Views: 3443
Reputation: 5903
It turns out that this was basically not (safely) possible until Ivy. Now in Angular 9/10 we can lazy load feature-modules without the router very easily.
StackBlitz
V13 StackBlitz Update
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
constructor(
private compiler: Compiler,
private injector: Injector
){ }
public ngOnInit(): void {
if (loggedin) {
this.loadModule(await import('./lazy/lazy.module').then(m => m.LazyModule));
} else {
this.loadModule(await import('./lazy2/lazy2.module').then(m => m.Lazy2Module));
}
}
async loadModule(module: Type<any>) {
let ref;
try {
this.container.clear();
// Angular < 13
const moduleFactory = await this.compiler.compileModuleAsync(module);
const moduleRef: any = moduleFactory.create(this.injector);
const componentFactory = moduleRef.instance.resolveComponent(); // ASSERTION ERROR
ref = this.container.createComponent(componentFactory, null, moduleRef.injector);
// Angular 13 update
const moduleRef = createNgModuleRef(module, this.injector);
const componentFactory = moduleRef.instance.resolveComponent();
ref = container.createComponent(
componentFactory,
undefined,
moduleRef.injector
);
} catch (e) {
console.error(e);
}
return ref;
}
}
Upvotes: 3
Reputation: 725
I believe what you intend to achieve is not possible through guards. Angular searches the routes array from top to bottom and as soon as it gets a path match, the corresponding module/component is loaded. In your case, { path: '', loadChildren: './feed/feed.module#FeedModule', canActivate: [IsAuthenticationGuard] }
is a url path match and thus Angular loads the Feed Module, however does not display anything as the guard returns failure. It doesn't even proceed to check the url match for line below.
Instead what you can do is,
{ path: '', loadChildren:'./home/home.module#HomeModule', canActivate: [IsAuthenticationGuard] },
I hope this solves your purpose.
Upvotes: 0
Reputation: 1158
Try maybe this:
const routes: Routes = [
{ path: '', redirectTo: condition ? 'home' : 'feed', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'feed', component: FeedComponent },
{ path: '*', redirectTo: 'home', pathMatch: 'full' },
];
That's not directly based on Guards, but you should probably be able to get your Guard return as the condition
Upvotes: -2
Reputation: 578
There are a couple things that you are doing wrong in my opinion.
Observable<boolean>
you don't need to map its value.Take a look at the official angular routing guide here. There is a lot of useful information that will help you. Especially these:
EDIT 2018/12/27
So if the question is how to conditionally load two feature modules on the same path,
the answer is, in my experience, you cannot.
Upvotes: 3