Please refer my project structure here I have create a project with multiple lazy loaded nested modules.
My requirement here is to conditionally load the feature child module as shown in the component login.component.ts, when the user login is failed he should be navigated to login(its working fine as LoginModule is already lazy loaded) and when login is successful user should be navigated to IntegratedPaymentsComponent present in IntegratedPmntsModule (which is not happening).
this.router.navigate(['integratedPayments']); -- is giving 'Uncaught (in promise): Error: Cannot match any routes 'integratedPayments'
I even tried loading the IntegratedPmntsModule using load() method of NgModuleFactoryLoader.load() which is giving 'module is not found error'
login.component.ts
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginFormGroup: FormGroup;
customerModel:CustomerLoginModel = new CustomerLoginModel();
userExist: Boolean = true;
constructor(private loginService: LoginService, private router: Router, private readonly loader: NgModuleFactoryLoader) { }
ngOnInit(): void {
this.loginFormGroup = new FormGroup({
customerId: new FormControl('', [Validators.required,Validators.maxLength(20),Validators.pattern('^[a-zA-Z0-9]+([._]?[a-zA-Z0-9]+)*$')]),
password: new FormControl('', [Validators.required, Validators.maxLength(15)])
})
}
submitLoginForm(formGroup: FormGroup): any{
this.customerModel.setCustomerId(formGroup.value.customerId);
this.customerModel.setPassword(formGroup.value.password);
this.loginService.authenticateCustomer(this.customerModel).subscribe(
response=>{
this.userExist=response},
error=>{
console.log(error)
}
);
if(this.userExist){
//this.loader.load('./app/integrate-pmnts-module/integrate-pmnts.module#IntegratePmntsModule').
//then(factory =>this.router.navigate(['integratedPayments']));
this.router.navigate(['integratedPayments']);
}
else
this.router.navigate(['login']);
}
}
app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginauthGuard } from './login/loginauth.guard';
const routes: Routes = [
{
path: 'login',
loadChildren: () => import('./login/login.module').then(mdule=>mdule.LoginModule),
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
login-routing.module.ts
const routes: Routes = [
{
path: '',
component: LoginComponent,
//canDeactivate: [LoginauthGuard]
},
{
path: 'integratedPayments',
loadChildren: () => import('../integrate-pmnts-module/integrate-pmnts.module').then(mdule=>mdule.IntegratePmntsModule)
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LoginRoutingModule {
}
login.component.html
<html>
<form [formGroup]="loginFormGroup" (ngSubmit)="submitLoginForm(loginFormGroup)">
Customer Id:<input type="text" formControlName="customerId" placeholder="Enter Customer ID"><br><br>
Password: <input type="password" formControlName="password" placeholder="Enter Password"><br><br>
<div *ngIf='!userExist'>
Please enter valid credentials!
</div><br><br>
<button class="pmntButton">Login</button>
</form>
</html>
integratepayments-routing.module.ts
const routes: Routes = [
{
path: '',
component: IntegratedPaymentsComponent
},
{
path: 'eftPaymentsPage',
loadChildren: () => import('src/app/integrate-pmnts-module/eft-payments-module/eft-payments-module').then(mod=>mod.EftPaymentsModuleModule)
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class IntegratedPaymentsRoutingModule { }
Since the integratedPayments
route is a child of login
route, you should use: this.router.navigateByUrl('login/integratedPayments')
.
This might not still work though, because the routes from login-routing.module.ts
are defined as follows:
const routes: Routes = [
{
path: '',
component: LoginComponent,
//canDeactivate: [LoginauthGuard]
},
{
path: 'integratedPayments',
loadChildren: () => import('../integrate-pmnts-module/integrate-pmnts.module').then(mdule=>mdule.IntegratePmntsModule)
}
];
which means that the first route (path: ''
) will always match. What you can do in order to avoid this is to add the pathMatch: 'full'
option:
const routes: Routes = [
{
path: '',
component: LoginComponent,
pathMatch: 'full'
},
{
path: 'integratedPayments',
loadChildren: () => import('../integrate-pmnts-module/integrate-pmnts.module').then(mdule=>mdule.IntegratePmntsModule)
}
];
perfectly with 'button routerLink='integratePayments' class="pmntButton"'
this is because of how RouterLink
directive works internally.
Let's see what happens when you click on a button which has this directive:
@HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
state: this.state,
};
this.router.navigateByUrl(this.urlTree, extras);
return true;
}
get urlTree(): UrlTree {
return this.router.createUrlTree(this.commands, {
relativeTo: this.route, // !
queryParams: this.queryParams,
fragment: this.fragment,
preserveQueryParams: attrBoolValue(this.preserve),
queryParamsHandling: this.queryParamsHandling,
preserveFragment: attrBoolValue(this.preserveFragment),
});
}
as you can see, it's using relativeTo
option. this.route
is injected as private route: ActivatedRoute
.
What this means is that you can make it work with this.router.navigate(['integratedPayments']);
from you login component.
You'll have to first inject the ActivatedRoute
inside login component and then add the relativeTo
option to route.navigate
:
this.router.navigate(['integratedPayments'], { relativeTo: this.route });