Lazy Loading in Angular

Lazy Loading in Angular: Speed Up Your App with Smarter Loading

If you've ever clicked on a website in your browser but still found yourself waiting... and waiting... for it to load, you're not alone.

According to Google (2023), as many as 53% of internet users will abandon a site that takes longer than three seconds to load. Performance isn't just a nice add-on—it's crucial.

Come into your surreptitious weapon: lazy loading.

If you’re developing a sales platform or written content website, no matter what form you create this app in, let it never lose its sprightliness.

When you finish reviewing this post, you will be equipped with:

  1. All knowledge on what lazy loading is, as well as just how much of a transformation it can bring to your app's performance.
  2. A checklist for easy implementation in your own Angular apps.
  3. Pro tips to help you avoid common mistakes.

As a bonus, we'll also give you a few practical examples so that you can see how it all works out in real life.

Let’s bring in the age of modular loading! 🚀

What Is Lazy Loading and Why Should You Care?

Lazy loading is a design pattern that defers the loading of non-critical resources, such as JavaScript modules, until they're needed.

Your entire app doesn't have to be loaded the moment a user enters—it gets broken into smaller parts, and Angular fetches them on demand.

Lazy Loading’s Benefits:

Big reduction in initial load time – Key features of your app are sprinting before your users’ eyes.
Less mobile data consumption – Shrink your payload.
Sub-Slid Performance – Smaller bundles mean faster parsing and execution.
Good ability to scale – Organize your code by feature modules, reducing complexity.

How Lazy Loading Works in Angular

One of the ways Angular achieves structural laziness is by making use of loaded router modules.

Router and NgModule are used by Angular to implement lazy loading. It works like this:

  1. A visitor moves to a route (e.g., /products).
  2. Angular determines whether the associated module has been loaded.
  3. If not, it fetches the module asynchronously and imports it into the application.
  4. Components inside that module are then rendered.

Step-by-Step Guide to Implementing Lazy Loading

Building a simple app with a lazy-loaded ProductsModule

Step 1: Generate a Feature Module

Generate a module with routing:

ng generate module products --route products --module app

This will create:

  • products.module.ts(NgModule)
  • products-routing.module.ts(Route configuration)
  • A component for the route

Step 2: Configure Routes for Lazy Loading

Update app-routing.module.ts:

const routes: Routes = [
  { path: 'products', loadChildren: () => import('./products/products.module').then(m => m.ProductsModule) },
  // Other routes...
];

🔹 loadChildren specifies the module’s path and dynamically imports it.
🔹 ProductsModule must define its own routes in products-routing.module.ts.

Step 3: Define Child Routes in the Feature Module

Inside products-routing.module.ts:

const routes: Routes = [
  { path: '', component: ProductsListComponent },
  { path: ':id', component: ProductDetailComponent }
];

Step 4: Check Lazy Loading in Action

Run your app and check the browser's Network tab. You will see:

✅ Navigate to /products.
✅ A new chunk (e.g., products-module.js) is loaded on the fly.

Real-World Example: E-Commerce App Optimization

Scenario:

An online store with over 10 product categories.

Problem:

The initial bundle was 5MB, causing slow load times.

Solution:

  • Each category's module is lazy-loaded.
  • Frequently visited pages are preloaded.

Result:

The initial bundle was reduced to 1.2MB, improving load times by 40%.

Best Practices for Lazy Loading

Group related features – Components, services, and routes should be divided logically per module.
Preload strategically – Load non-essential modules in the background.
Avoid over-splitting – Too many chunks can increase HTTP overhead.
Trace bundle sizes – Use the Webpack Bundle Analyzer to monitor code splits.


Common Traps and How to Escape

🚨 Circular Dependencies: Ensure modules don’t import each other.
🚨 Missing Route Definitions: Check loadChildren paths and module exports.
🚨 Ignoring Preloading: Balance lazy loading and preloading for optimal UX.


Case Study: How Company X Reduced Load Time for Their SaaS Platform

Problem:

A dashboard with 15+ feature tabs, making the initial load slow.

Solution:

  • Each tab module was loaded lazily.
  • Role-based access was added.

Result:

  • Load time dropped from 8 seconds to 2 seconds.
  • User engagement increased by 35%.

In Conclusion: Lazy Loading Means Faster Apps and Happier Users

Lazy loading isn’t just a performance boost—it’s an essential practice for Angular developers today.

By breaking your application into modular parts, you create fast, scalable, and efficient experiences that keep users engaged.

Angular router tutorial

Angular Router Setup: Your Blueprint for Smooth Navigation in Single-Page Apps

Imagine a website where every click necessitated a reload. Frustrating, isn’t it? Single-page apps can ensure such frustration doesn't come to life. And in this seamless navigation model, Angular Router is the secret weapon. Whether you are building an e-commerce platform or a portfolio site, Angular Router lets you create fast, dynamic user experiences without full page refreshes.

You will learn in this guide how to:

  • Configure an Angular Router from scratch
  • Employ lazy loading to get better performance
  • Use Guards to protect routes
  • Choose sensible detail information and warning sounds that are both scalable and maintainable

Let us make your Angular app a well-connected navigation powerhouse!

What Is Angular Router and Why Does It Matter?

Angular Router is a powerful library that maps URLs to components so that users can flip between views without reloading the page. It’s indispensable for:

  • SPA efficiency: Faster transitions between pages
  • Bookmarkable URLs: Users can save or share particular views
  • Modular design: Organizing code into feature modules

Optimization Tidbit: When optimized correctly, HTTP Archive says SPAs (single-page applications) actually load 30-50% faster than traditional multi-page sites in terms of initial loading times.

Step 1: Installing Angular Router

If you’re beginning a new project, routing comes baked into Angular CLI by default. For existing projects, you can add it like so:

ng generate module app-routing --flat --module=app  

This creates an app-routing.module.ts file and imports it into your AppModule.

Step 2: Basic Route Configuration

Define your routes in app-routing.module.ts:

import { NgModule } from '@angular/core';  
import { RouterModule, Routes } from '@angular/router';  
import { HomeComponent } from './home/home.component';  
import { AboutComponent } from './about/about.component';  
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';  

const routes: Routes = [  
  { path: '', component: HomeComponent },  
  { path: 'about', component: AboutComponent },  
  { path: '**', component: PageNotFoundComponent } // Wildcard route for 404  
];  

@NgModule({  
  imports: [RouterModule.forRoot(routes)],  
  exports: [RouterModule]  
})  
export class AppRoutingModule { }  

Main Points for Summary:

  • path: '' sets the default route (e.g., / redirects t0 HomeComponent).
  • path: '**' catches unmatched URLs (e.g., /invalid-route).

Step 3: Adding Navigation with Router Links

Use routerLink directives in your template instead of <a href> to avoid full-page reloads.

<nav>  
  <a routerLink="/" routerLinkActive="active">Home</a>  
  <a routerLink="/about" routerLinkActive="active">About</a>  
</nav>  

Pro Tip: routerLinkActive="active" adds a CSS class to the active link for styling.

Step 4: Dynamic Routes with Parameters

Grab URL parameters (e.g., product IDs) by means of /:id:

const routes: Routes = [  
  { path: 'products/:id', component: ProductDetailComponent }  
];  

Access the Parameter in Your Component:

import { ActivatedRoute } from '@angular/router';  
export class ProductDetailComponent {  
  constructor(private route: ActivatedRoute) {  
    this.route.params.subscribe(params => {  
      console.log('Product ID:', params['id']);  
    });  
  }  
}  

Step 5: Lazy Loading for Faster Load Times

Lazy loading pushes the loading of modules back until later, so that initial bundle size can be small.

  1. Create a Feature Module:
ng generate module products --route products --module app  
  1. Update Routes:
const routes: Routes = [  
  { path: 'products', loadChildren: () => import('./products/products.module').then(m => m.ProductsModule) }  
];  

This ensures that the ProductsModule is only loaded if the user navigates to /products.

Step 6: Protecting Routes with Guards

Guards are used to restrict access (e.g., ensure that a user is authenticated).

  1. Make an Auth Guard:
import { Injectable } from '@angular/core';  
import { CanActivate, Router } from '@angular/router';  

@Injectable({ providedIn: 'root' })  
export class AuthGuard implements CanActivate {  
  constructor(private router: Router) {}  
  canActivate(): boolean {  
    const isLoggedIn = false; // Look up the user's auth status  
    if (!isLoggedIn) this.router.navigate(['/login']);  
    return isLoggedIn;  
  }  
}  
  1. Apply the Guard to Routes:
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }  

Angular Router Best Practices

  1. Organize Routes Logically: Group related routes into feature modules.
  2. Use Lazy Loading: Prioritize performance.
  3. Avoid Hardcoding URLs: Use named constants for paths.
  4. Handle 404s: Always include a wildcard route.

Navigate Your Angular App Like a Pro

Angular Router gives your app the feel of being seamless and smooth. By mastering route configuration, lazy loading modules, and guards, you’ll create SPAs that are responsive and fast.


With this guide, you can structure the navigation in your app to be logical and high-performance. Happy routing!

Mastering Reactive Forms in Angular

If you are attempting to build a sign-up form that changes according to user input, such as supplying additional fields when someone selects “Business Account,” in addition to real-time password validation, it would be difficult. Not with Angular reactive forms!

Reactive forms afford developers superior control over form logic, validation, and dynamic behavior. For complex apps, they are indeed the best. Whether building a multi-step checkout flow or conducting a survey, reactive forms are your friend.

By the time you finish this post, you will know how to:

  • Build reactive forms with clean, maintainable code.
  • Add dynamic form fields and custom validation.
  • Handle complex situations such as nested forms and cross-field validation.
  • Avoid common errors

Ready to enhance your skills with Angular? Let’s start!

What Exactly Are Reactive Forms in Angular?

Reactive forms (also known as "model-driven" forms) in Angular are a way of programmatically handling forms. Unlike template-driven forms, which are directed by HTML tags, reactive forms use TypeScript classes like FormGroup, FormControl, and FormArray to manage form logic entirely. This method gives us unparalleled flexibility in creating dynamic and scalable forms.

Key Advantages of Reactive Forms

  • Explicit Control: Code your form structure and validation rules.
  • Dynamic Behavior: Programmatically add or remove fields in a form.
  • Reactive Programming: Take advantage of tools like valueChanges for real-time updates.
  • Complex Validation: Support for cross-field validation and custom rules.

When Should You Use Reactive Forms Over Template-Driven Forms?

Feature Reactive Forms Template-Driven Forms
Complexity Best for complex forms Ideal for simple forms
Control Programmatic (TypeScript) Declarative (HTML)
Validation Custom and dynamic rules HTML5 and basic validators
Testing Easier for unit testing Requires DOM testing

Pro Tip: According to the 2023 Stack Overflow Survey, 68% of Angular developers choose reactive forms for enterprise applications due to their scalability.

Build Your First Reactive Form: A Step-by-Step Guide

Here, we’ll set up a user registration form with dynamic password validation.

Step 1: Import ReactiveFormsModule

In your AppModule, import ReactiveFormsModule:

import { ReactiveFormsModule } from '@angular/forms';  
@NgModule({  
  imports: [ReactiveFormsModule],  
})  
export class AppModule {}  

Step 2: Define Form Structure in Component

Use FormBuilder to simplify form creation:

import { FormBuilder, Validators } from '@angular/forms';  
export class RegistrationComponent {  
  constructor(private fb: FormBuilder) {}  
  registrationForm = this.fb.group({  
    email: ['', [Validators.required, Validators.email]],  
    password: ['', [  
      Validators.required,  
      Validators.minLength(8),  
      Validators.pattern(/^(?=.*[A-Z])(?=.*\d).+$/)  
    ]],  
    newsletter: [false]  
  });  

  onSubmit() {  
    if (this.registrationForm.valid) {  
      console.log('Form Data:', this.registrationForm.value);  
    }  
  }  
}  

Step 3: Bind Template to the Form

<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">  
  <label>Email: <input formControlName="email" /></label>  
  <label>Password: <input type="password" formControlName="password" /></label>  
  <label>Subscribe to Newsletter? <input type="checkbox" formControlName="newsletter" /></label>  
  <button type="submit">Sign Up</button>  
</form>  

Add Real-Time Validation and Error Messages

Use FormControl to display friendly, human-readable error messages:

<div *ngIf="registrationForm.get('email').hasError('required')">  
  Email is required.  
</div>  
<div *ngIf="registrationForm.get('email').hasError('email')">  
  Invalid email format.  
</div>  

Pro Tip: To safely access individual controls, use registrationForm.get('fieldName').

Handling Dynamic Form Fields with FormArray

Want users to enter multiple email addresses? Use FormArray:

Component:

emails = this.fb.array([this.fb.control('')]);  
addEmail() {  
  this.emails.push(this.fb.control(''));  
}  

Template:

<div formArrayName="emails">  
  <div *ngFor="let email of emails.controls; let i = index">  
    <input [formControlName]="i" />  
  </div>  
</div>  
<button (click)="addEmail()">Add Email</button>  

Reactive Forms: Pros and Cons

👍 Advantages

  • Complete Control: Best for complex workflows.
  • Reactive Approach: Uses RxJS for features like debouncing inputs.
  • Testing Made Easy: Logic is in TypeScript, making unit tests easier.

👎 Disadvantages

  • Steep Learning Curve: Requires mastery of FormControl and FormGroup.
  • More Boilerplate: More setup than template-driven forms.

Case Study: How Company X Improved Their SaaS Business

A small fintech startup transformed into a top brand by switching from template-driven to reactive forms.

Outcomes:

  • 40% fewer submission errors.
  • 25% faster response time.

Conclusion: Build Robust Angular Forms

By mastering FormGroup, FormControl, and FormArray, you can create powerful, scalable forms.

Your Next Steps:

  1. Experiment with the form project above.
  2. Add a custom validator (e.g., Confirm Password).

Found This Guide Useful? Share it with your friends 

Angular Template-Driven Forms

Mastering Template-Driven Forms in Angular: A Beginner’s Guide to Making Form Handling Effortless

When you set out to build a web application, don't think that forms go unnoticed. From a simple login screen to the sign-up page of a new service, into feedback forms for users at any point in their interaction with your service. However, they are just user input supported by digital systems—their power is still limited deeply down to each individual field! But creating them can feel daunting—particularly if you're new to Angular.

Template-driven forms are Angular's way of taking form handling into its own hands, allowing you to build dynamic and validated forms without writing much code at all. In this guide, we show you how to use this powerful feature for a seamless user experience even as a beginner.

By the End of This Article, You'll Be Able To:

  • Build a template-driven form from scratch.
  • Set up real-time validation to check your data input.
  • Manage form submission like it's your job!
  • Learn where others fall into traps and how you can avoid them.

Let's get started!

template driven forms in angular


What Are Template-Driven Forms in Angular Exactly?

Angular's template-driven forms make it almost natural to build forms. You don't need separate TypeScript code but can define form logic directly in your HTML. Unlike reactive forms, which utilize the FormControl moved into TypeScript (where it gets ugly indeed!), template-driven forms use Angular directives such as NgModel, NgForm, and NgModelGroup to automate most of the heavy lifting.

Characteristics of Template-Driven Forms

  • Two-Way Data Binding: Use (ngModel) to bind data between your component and template seamlessly.
  • Automatic Form Control: Behind the scenes, Angular is creating FormControl instances by default unless you specify otherwise.
  • Built-in Validation: Use HTML5 validation attributes (required, email) together with Angular's custom validators.

Your First Template-Driven Form from Scratch, Step by Step

Now, let's put template-driven forms into real-world practice with a simple user login form.

Step 1: Set Up the Angular Module

Make sure your AppModule includes FormsModule:

import { FormsModule } from '@angular/forms';  
@NgModule({  
  imports: [FormsModule],  
})  
export class AppModule {}  

Step 2: Create the Template for the Form

<form #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)">  
  <label for="email">Email:</label>  
  <input type="email" id="email" name="email" ngModel required email>  
  
  <label for="password">Password:</label>  
  <input type="password" id="password" name="password" ngModel required minlength="6">  
  
  <button type="submit" [disabled]="!loginForm.valid">Log In</button>  
</form>  

Step 3: Handle Form Submission in Your Component

onSubmit(form: NgForm) {  
  if (form.valid) {  
    console.log('Form Data:', form.value);  
    // Send data to your backend here  
  }  
}  

Explanation:

  • #loginForm="ngForm" provides a reference to the form's NgForm instance.
  • ngModel binds input values with your component.
  • (ngSubmit) is triggered when the user submits the form.

Adding Validation and Error Messages

Validation is vital to ensure that our input is a legal and meaningful data point. Here's how to present user-friendly error messages:

<div *ngIf="email.invalid && email.touched">  
  <span *ngIf="email.errors?.required">Email required.</span>  
  <span *ngIf="email.errors?.email">Incorrect format for email.</span>  
</div>  

<div *ngIf="password.invalid && password.touched">  
  <span *ngIf="password.errors?.required">Password is required.</span>  
  <span *ngIf="password.errors?.minlength">Password should contain at least 6 characters.</span>  
</div>  

Pro Tip: Use touched to show errors only after the user interacts with the field.

Advantages and Disadvantages of Template-Driven Forms

👍 Pros

  • Easy Setup: Perfect for simple forms.
  • Less Boilerplate: No need to manually declare FormControls.
  • Familiar Syntax: Uses HTML and data binding, suitable for beginners.

👎 Cons

  • Limited Control: Difficult to perform things such as complex form management or dynamic validation with this model.
  • Testing Challenges: The logic is in the template which makes unit tests harder.

Tips for Writing Template-Driven Forms

  1. Keep It Simple: Template-driven forms are best for simple use cases like logins, and contact forms.
  2. Use Built-in Validators: Combine custom Angular validators with HTML5 attributes for the strongest checks.
  3. Organize Code Structure: Place complex logic in components where it makes sense.
  4. Use NgModelGroup for Grouping: Group related fields such as billing and shipping addresses together.

Template-driven forms are a boon for Angular developers who demand simplicity as well as speed. By mastering directives like NgModel and NgForm, you can create user-friendly forms without writing a lot of code.

What Next for You?

  1. Try out the login form example above.
  2. For more advanced situations, experiment with custom validators.
  3. Angular's Reactive Forms will take care of the trickiest scenarios.


How to pass data between components using routes in Angular?

Techniques to Share Routes Data in Angular—How Efficient Communication Works Among Components of an Angular Application

In the world of Angular applications, components often need to share data, especially as they move from view to view. While services and state management libraries such as NgRx are often the answer, Angular's routing provides some lightweight techniques for passing information directly along routes.

If you're building a product detail page, search filter, multi-step form, or something else entirely, you need to learn how to transfer or pass data through routes. This guide demonstrates several methods with practical examples and advice on best practices.

How to Pass Data Between Components Using Routes in Angular

1. The Need to Share Data via Routes

  • Stateless Navigation: Prevent simple data transfer from becoming overly dependent (and inducing spaghetti code in your otherwise clean services or components).
  • Bookmarkable URLs: Keeping data in the URL ensures users can return to their entry anytime without any problem.
  • Lightweight: Designed for tiny, transient pieces of information like IDs and filters.

2. Passing Data via Routes

Route Parameters

Use Case: Passing key data, such as an ID (e.g., /products/123).

Implementation

Define the Route:

// app-routing.module.ts
const routes: Routes = [
  { path: 'product/:id', component: ProductDetailComponent }
];

Navigate with the Parameter:

// product-list.component.ts
navigateToProduct(id: number) {
  this.router.navigate(['/product', id]);
}

Retrieve the Parameter:

// product-detail.component.ts
import { ActivatedRoute } from '@angular/router';

export class ProductDetailComponent {
  constructor(private route: ActivatedRoute) {
    this.route.paramMap.subscribe(params => {
      const id = params.get('id');
      // Fetch product details using the ID
    });
  }
}

Query Parameters

Use Case: Passing optional data such as filters or sorting options (e.g., /products?category=books).

Implementation

Navigate with Query Params:

// product-list.component.ts
applyFilter(category: string) {
  this.router.navigate(['/products'], { queryParams: { category: category } });
}

Retrieve the Query Parameter:

// product-list.component.ts
this.route.queryParamMap.subscribe(params => {
  const category = params.get('category');
  // Filter products according to category
});

Route Data Property

Use Case: Passing static or resolved data (e.g., page titles, permissions).

Using Data in Route Configuration

Define Static Data:

// app-routing.module.ts
{
  path: 'dashboard',
  component: DashboardComponent,
  data: { requiresAuth: true, title: 'User Dashboard' }
}

Access the Data:

// dashboard.component.ts
ngOnInit() {
  this.route.data.subscribe(data => {
    console.log(data.title); // Output: "User Dashboard"
  });
}

Dynamic Data with Resolvers

Create a Resolver:

// product.resolver.ts
@Injectable({ providedIn: 'root' })
export class ProductResolver implements Resolve {
  constructor(private productService: ProductService) {}

  resolve(route: ActivatedRouteSnapshot) {
    return this.productService.getProduct(route.params['id']);
  }
}

Configure the Route with Resolver:

// app-routing.module.ts
{
  path: 'product/:id',
  component: ProductDetailComponent,
  resolve: { product: ProductResolver }
}

Retrieve the Resolved Data:

// product-detail.component.ts
ngOnInit() {
  this.route.data.subscribe(data => {
    this.product = data.product;
  });
}

State Object (NavigationExtras)

Use Case: Passing temporary or sensitive data without putting it in the URL.

Implementation

Navigate with State:

// checkout.component.ts
proceedToPayment() {
  this.router.navigate(['/payment'], { state: { cartItems: this.cartItems } });
}

Retrieve the State:

// payment.component.ts
ngOnInit() {
  this.cartItems = history.state.cartItems;
}

Practical Example: User Profile Editor

Scenario

Pass a user ID via route parameters and use a resolver to retrieve user data.

Route Configuration

{
  path: 'profile/:userID',
  component: ProfileComponent,
  resolve: { user: UserResolver }
}

Create Resolver:

// user.resolver.ts
resolve(route: ActivatedRouteSnapshot) {
  return this.userService.getUser(route.params['userId']);
}

Retrieve Data in Component:

// profile.component.ts
ngOnInit() {
  this.route.data.subscribe(data => {
    this.user = data.user;
  });
}

Best Practices

  • Use Route Parameters for Necessary Data: Keep URLs neat and meaningful.
  • Limit State Object Size: Avoid passing large objects (risk of data loss on page reload).
  • Resolvers over Route Data: Ensure data is loaded before the component is initialized.
  • Encode Sensitive Information: Do not expose sensitive information in URLs.
  • *Use trackBy with ngFor: Optimize performance when rendering lists from route data.

Angular provides various ways to transfer data between components through routes: from simple IDs in URLs to complex resolved data. By making the right choices in route parameters, query parameters, resolvers, and state objects, you can create flexible, user-friendly applications.

Pay attention to both security and performance, and choose the method that best fits your use case.

Creating custom directives in angular

 Creating Custom Data Directives

Step 1: Build an Attribute Directive

Example: Auto-Format Text on Input

  1. Create the directive:
ng generate directive autoFormat
  1. Define its behavior:
// auto-format.directive.ts
@Directive({
 selector: '[appAutoFormat]'
})
export class AutoFormatDirective {
 @HostListener('input', ['$event']) onInput(event: Event) {
  const input = event.target as HTMLInputElement;
  input.value = input.value.toUpperCase();
 }
}
  1. Use it in a template:
<input appAutoFormat placeholder="Type in uppercase">

Step 2: Build a Structural Directive

Example: Delay Element Rendering

  1. Create the directive:
ng generate directive delayRender
2.define logic:
// delay-render.directive.ts  
@Directive({  
  selector: '[appDelayRender]'  
})  
export class DelayRenderDirective {  
  constructor(  
    private templateRef: TemplateRef<any>,  
    private viewContainer: ViewContainerRef  
  ) {}  

  @Input() set appDelayRender(delay: number) {  
    setTimeout(() => {  
      this.viewContainer.createEmbeddedView(this.templateRef);  
    }, delay);  
  }  
}  
3.use it in template:
<div *appDelayRender="2000">This content renders after 2 seconds.</div>  
Select Menu