Skip to content

Routing & Forms

Routing: Angular's RouterModule maps URL paths to components. Supports lazy loading, route guards, and nested routes. Forms: Two approaches — Template-driven (simpler, uses ngModel) and Reactive (more control, uses FormGroup/FormControl in TypeScript). Reactive forms are preferred for complex validation.


RouterModule & Configuration

Define routes as an array of { path, component } objects. Use RouterModule.forRoot(routes) in the root module. <router-outlet> is the placeholder where routed components render. Navigate with routerLink directive or Router.navigate().

Deep Dive: Route Config & Navigation
// app-routing.module.ts
const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: 'users', component: UserListComponent },
    { path: 'users/:id', component: UserDetailComponent },  // route param
    { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] },
    { path: '**', component: NotFoundComponent }             // wildcard — 404
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }
<!-- Navigation -->
<nav>
    <a routerLink="/home" routerLinkActive="active">Home</a>
    <a routerLink="/users" routerLinkActive="active">Users</a>
</nav>

<!-- Routed component renders here -->
<router-outlet></router-outlet>
// Programmatic navigation
constructor(private router: Router, private route: ActivatedRoute) {}

goToUser(id: number) {
    this.router.navigate(['/users', id]);
}

// Read route params
ngOnInit() {
    this.route.params.subscribe(params => {
        this.userId = +params['id'];  // + converts to number
    });
}

Lazy Loading

Lazy loading loads feature modules on demand (only when the user navigates to that route). Reduces initial bundle size. Use loadChildren with dynamic import syntax. Each lazy-loaded module has its own routing with RouterModule.forChild().

Deep Dive: Example
// app-routing.module.ts
const routes: Routes = [
    { path: 'home', component: HomeComponent },
    {
        path: 'admin',
        loadChildren: () => import('./admin/admin.module')
            .then(m => m.AdminModule)       // lazy-loaded!
    }
];

// admin/admin-routing.module.ts
const adminRoutes: Routes = [
    { path: '', component: AdminDashboardComponent },
    { path: 'users', component: AdminUsersComponent }
];

@NgModule({
    imports: [RouterModule.forChild(adminRoutes)]  // forChild, not forRoot
})
export class AdminRoutingModule { }

Route Guards

Guards control access to routes. CanActivate — can the user navigate to this route? CanDeactivate — can the user leave? (unsaved changes). Resolve — pre-fetch data before route loads. Guards return boolean, Observable<boolean>, or UrlTree (redirect).

Deep Dive: AuthGuard Example
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
    constructor(private authService: AuthService, private router: Router) {}

    canActivate(route: ActivatedRouteSnapshot): boolean | UrlTree {
        if (this.authService.isLoggedIn()) {
            return true;
        }
        return this.router.createUrlTree(['/login']);  // redirect
    }
}

// Usage in routes
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }

Template-driven Forms

Uses FormsModule. Two-way binding with [(ngModel)]. Validation via HTML attributes (required, minlength). Angular auto-creates NgForm and NgModel directives. Simpler for basic forms but harder to test and scale.

Deep Dive: Example
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
    <input
        name="name"
        [(ngModel)]="user.name"
        required
        minlength="3"
        #name="ngModel">

    <div *ngIf="name.invalid && name.touched" class="error">
        <span *ngIf="name.errors?.['required']">Name is required</span>
        <span *ngIf="name.errors?.['minlength']">Min 3 characters</span>
    </div>

    <input name="email" [(ngModel)]="user.email" required email #email="ngModel">

    <button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>
onSubmit(form: NgForm) {
    if (form.valid) {
        console.log(form.value);  // { name: '...', email: '...' }
    }
}

Reactive Forms

Uses ReactiveFormsModule. Form structure defined in TypeScript with FormGroup, FormControl, FormArray. Validation via Validators. More powerful: dynamic forms, custom validators, easier testing. Preferred for complex forms.

Deep Dive: Example
@Component({ selector: 'app-user-form' })
export class UserFormComponent implements OnInit {
    userForm!: FormGroup;

    constructor(private fb: FormBuilder) {}

    ngOnInit() {
        this.userForm = this.fb.group({
            name: ['', [Validators.required, Validators.minLength(3)]],
            email: ['', [Validators.required, Validators.email]],
            address: this.fb.group({          // nested group
                street: [''],
                city: ['', Validators.required]
            }),
            hobbies: this.fb.array([])        // dynamic array
        });
    }

    addHobby() {
        (this.userForm.get('hobbies') as FormArray)
            .push(this.fb.control('', Validators.required));
    }

    onSubmit() {
        if (this.userForm.valid) {
            console.log(this.userForm.value);
        }
    }
}
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
    <input formControlName="name">
    <div *ngIf="userForm.get('name')?.invalid && userForm.get('name')?.touched">
        Name is required (min 3 chars)
    </div>

    <input formControlName="email">

    <div formGroupName="address">
        <input formControlName="street" placeholder="Street">
        <input formControlName="city" placeholder="City">
    </div>

    <button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>
Feature Template-driven Reactive
Module FormsModule ReactiveFormsModule
Binding [(ngModel)] formControlName
Structure Template TypeScript class
Validation HTML attributes Validators class
Testing Harder Easier
Best for Simple forms Complex, dynamic forms

Common Interview Questions

Common Interview Questions
  • How does Angular routing work?
  • What is lazy loading? How do you implement it?
  • What are route guards? Name the types.
  • What is the difference between template-driven and reactive forms?
  • How do you validate forms in Angular?
  • What is FormGroup, FormControl, FormArray?
  • What is routerLink vs Router.navigate()?
  • How do you read route parameters?