Full Trust European Hosting

BLOG about Full Trust Hosting and Its Technology - Dedicated to European Windows Hosting Customer

AngularJS Hosting Europe - HostForLIFE :: Angular Unit Testing File Upload

clock August 4, 2026 12:42 by author Peter

HTML Template
<input
  id="myFile"
  type="file"
  (change)="onFileSelected()"
  #fileInput
/>

Whenever the user selects a file, the change event calls the onFileSelected() method.

Component
import { Component } from '@angular/core';

@Component({
  selector: 'app-input-file',
  templateUrl: './input-file.component.html'
})
export class InputFileComponent {

  uploadedFile!: File;

  onFileSelected(): void {

    const inputNode = document.querySelector('#myFile') as HTMLInputElement;

    if (inputNode.files && inputNode.files.length > 0) {
      this.uploadedFile = inputNode.files[0];
      console.log(this.uploadedFile);
    }

  }

}


How It Works
When the user selects a file:

  • The component locates the file input element.
  • The browser stores the selected file(s) in the files collection.
  • The first file is assigned to the uploadedFile property.
  • Although this works, Angular recommends avoiding direct DOM access where possible.

Writing the Unit Test
The browser normally populates the files property, so during unit testing we need to mock it ourselves.
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { InputFileComponent } from './input-file.component';

describe('InputFileComponent', () => {

  let component: InputFileComponent;
  let fixture: ComponentFixture<InputFileComponent>;

  beforeEach(async () => {

    await TestBed.configureTestingModule({
      declarations: [InputFileComponent]
    }).compileComponents();

    fixture = TestBed.createComponent(InputFileComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

  });

  it('should store the selected file', () => {

    const file = new File(
      ['Dummy Content'],
      'sample.txt',
      {
        type: 'text/plain'
      }
    );

    const input = fixture.nativeElement.querySelector('#myFile');

    Object.defineProperty(input, 'files', {
      value: [file]
    });

    input.dispatchEvent(new Event('change'));

    expect(component.uploadedFile).toEqual(file);

  });

});

Understanding the Test
Step 1: Create a Mock File

const file = new File(
  ['Dummy Content'],
  'sample.txt',
  {
    type: 'text/plain'
  }
);


This creates a fake File object that behaves exactly like a file selected by the user.

Step 2: Mock the Browser's files Property
Object.defineProperty(input, 'files', {
  value: [file]
});



Since the browser owns the files property, we replace it with our mock file during testing.

Step 3: Simulate File Selection
input.dispatchEvent(new Event('change'));

This triggers the same event that occurs when a user selects a file.

Step 4: Verify the Result

expect(component.uploadedFile).toEqual(file);

The test passes if the component correctly stores the selected file.

A Better Angular Approach
Instead of querying the DOM with document.querySelector(), Angular encourages passing the event object directly.
Template
<input
  type="file"
  (change)="onFileSelected($event)"
/>


Component
onFileSelected(event: Event): void {

  const input = event.target as HTMLInputElement;

  if (!input.files?.length) {
    return;
  }

  this.uploadedFile = input.files[0];

}


This approach is:

  • More Angular-friendly
  • Easier to unit test
  • Doesn't directly access the DOM
  • Better for maintainability

Unit Test for the Improved Version
it('should store the selected file', () => {

  const file = new File(
    ['Angular Testing'],
    'document.pdf',
    {
      type: 'application/pdf'
    }
  );

  const event = {
    target: {
      files: [file]
    }
  } as unknown as Event;

  component.onFileSelected(event);

  expect(component.uploadedFile).toEqual(file);

});


Notice that we no longer need to manipulate the DOM. We simply create a mock event object and call the component method directly, making the unit test cleaner and easier to understand.

Conclusion
Unit testing file uploads in Angular is straightforward once you know how to mock the browser's files property. While older implementations often relied on document.querySelector(), modern Angular applications should use the event object passed by the change event. This results in cleaner code, simpler unit tests, and components that are easier to maintain.

The overall testing strategy is simple:

  • Create a mock File object.
  • Assign it to the input's files property (or pass it through the event object).
  • Trigger the change event.
  • Verify that the component stores the selected file correctly.

Following this approach will help you confidently test file upload functionality in any Angular application.



AngularJS Hosting Europe - HostForLIFE :: Understanding Angular Performance: Uncovering ChangeDetectorRef and NgZone

clock July 31, 2026 13:43 by author Peter

Performance problems in Angular apps are frequently caused by the way the framework refreshes the DOM and manages state changes. NgZone and ChangeDetectorRef (CDR) are two essential technologies used in this approach. Building responsive and effective Angular apps requires a grasp of how these APIs complement one another and when to utilize them, even though developers often come across them in performance optimization guidelines.

The Roles: "When" vs. "How"
To understand their relationship, think of Angular's rendering engine as a two-stage pipeline.

NgZone: Controls When Change Detection Runs

NgZone monitors asynchronous operations such as:

  • DOM events
  • HTTP requests
  • Timers (setTimeout and setInterval)
  • Promises
  • User interactions

Using Zone.js, Angular detects when an asynchronous task completes. If the task runs inside the Angular zone, Angular automatically triggers a global change detection cycle across the application.

ChangeDetectorRef: Controls How and Where Change Detection Runs

ChangeDetectorRef provides manual control over a component's view.

It allows you to:

  • Mark a component for checking using markForCheck()
  • Trigger an immediate change detection cycle using detectChanges()
  • Detach a component from Angular's change detection tree
  • Reattach a previously detached component
  • Unlike NgZone, which influences the entire application, ChangeDetectorRef focuses on a specific component.

Real-World Scenario: A High-Frequency Live Data Ticker
Imagine you're building a financial dashboard that receives stock or cryptocurrency prices every 100 milliseconds through a WebSocket or timer.

The Problem

If these updates are processed inside Angular's default zone, every update triggers a full application-wide change detection cycle.

With updates arriving every 100 milliseconds:

  • Angular performs approximately 10 change detection cycles per second.
  • CPU usage increases.
  • UI responsiveness decreases.
  • Input lag and animation stuttering become noticeable.


The Solution
A more efficient approach is to:

  • Execute the high-frequency background work outside Angular's zone using NgZone.runOutsideAngular().
  • Update the UI only when necessary using ChangeDetectorRef.detectChanges() or markForCheck().

How NgZone and CDR Cooperate
Example: Optimizing a Live Price Ticker

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  NgZone
} from '@angular/core';

@Component({
  selector: 'app-live-ticker',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div class="ticker-card">
      <h2>Live Bitcoin Price</h2>

      <p class="price">
        {{ currentPrice | currency:'USD' }}
      </p>

      <small>
        Background Processing Ticks: {{ rawTicks }}
      </small>
    </div>
  `
})
export class LiveTickerComponent implements OnInit, OnDestroy {

  currentPrice = 50000;
  rawTicks = 0;

  private timerId: any;

  constructor(
    private ngZone: NgZone,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {

    this.ngZone.runOutsideAngular(() => {

      this.timerId = setInterval(() => {

        this.rawTicks++;

        this.currentPrice += (Math.random() - 0.5) * 20;

        if (this.rawTicks % 10 === 0) {

          this.cdr.detectChanges();

        }

      }, 100);

    });

  }

  ngOnDestroy(): void {

    if (this.timerId) {

      clearInterval(this.timerId);

    }

  }

}


Code Breakdown
1. Use OnPush Change Detection

changeDetection: ChangeDetectionStrategy.OnPush

This prevents Angular from automatically checking the component during every global change detection cycle.

Instead, updates occur only when:

  • An input changes
  • An event occurs

The component is explicitly marked for checking
detectChanges() is called


2. Execute Background Work Outside Angular
this.ngZone.runOutsideAngular(() => {
    ...
});

The timer executes outside Angular's zone.

As a result:

  • Zone.js ignores each timer tick.
  • Angular does not perform global change detection every 100 milliseconds.

3. Perform Background Processing
this.rawTicks++;

this.currentPrice +=
    (Math.random() - 0.5) * 20;


The application continues processing incoming data without updating the DOM on every tick.

4. Update the UI Only When Needed

if (this.rawTicks % 10 === 0) {

    this.cdr.detectChanges();

}


Instead of updating the UI every 100 milliseconds, the component refreshes only once every second.

This significantly reduces rendering work while keeping the displayed data current.

How NgZone and ChangeDetectorRef Work Together
These APIs solve different problems but complement one another.

NgZone.runOutsideAngular()

  • Prevents unnecessary global change detection.
  • Ideal for high-frequency background operations.
  • Reduces CPU usage by isolating expensive asynchronous work.

ChangeDetectorRef.detectChanges()

  • Performs change detection only for the current component and its children.
  • Leaves the rest of the application untouched.
  • Provides precise control over when the UI is updated.

NgZone vs. ChangeDetectorRef

FeatureNgZoneChangeDetectorRef
Primary purpose Controls when Angular runs change detection Controls how and where change detection runs
Scope Entire Angular application Individual component
Typical use case High-frequency asynchronous operations Manual UI updates
Common methods run(), runOutsideAngular() detectChanges(), markForCheck(), detach(), reattach()
Performance benefit Prevents unnecessary global checks Updates only targeted components

When Should You Use NgZone?
Use NgZone when working with:

  • WebSocket streams
  • Timers
  • Canvas animations
  • High-frequency sensor data
  • Third-party JavaScript libraries
  • Background processing
  • Continuous polling

The goal is to prevent Angular from reacting to every asynchronous event.

When Should You Use ChangeDetectorRef?

Use ChangeDetectorRef when you need:

  • Manual UI updates
  • Better control with OnPush
  • Selective component rendering
  • Detached component trees
  • Performance optimization for complex views
  • It provides fine-grained control over Angular's rendering behavior.

Best Practices
For performance-sensitive Angular applications:

  • Use ChangeDetectionStrategy.OnPush whenever appropriate.
  • Execute high-frequency background work outside Angular's zone.
  • Use markForCheck() when the component should be refreshed during the next change detection cycle.
  • Use detectChanges() when an immediate UI update is required.
  • Avoid triggering unnecessary application-wide change detection.

Combining runOutsideAngular() with targeted ChangeDetectorRef updates is one of the most effective optimization techniques available in Angular.

Conclusion
Although NgZone and ChangeDetectorRef are closely related to Angular's change detection mechanism, they serve different purposes. NgZone determines when Angular should perform change detection by monitoring asynchronous operations, while ChangeDetectorRef determines how and where component views are updated.

Using them together enables Angular applications to process high-frequency background operations efficiently while minimizing unnecessary DOM updates. This approach improves responsiveness, reduces CPU usage, and helps build scalable, high-performance applications.



AngularJS Hosting Europe - HostForLIFE :: Developing Lightweight Desktop Applications: Tauri vs Electron

clock July 23, 2026 10:49 by author Peter

In contemporary software development, desktop apps continue to play a significant role. Developers continue to create cross-platform desktop solutions that function on Windows, macOS, and Linux, ranging from code editors and communication tools to productivity software and commercial apps. Platform-specific technologies were formerly needed to create desktop programs, leading to distinct codebases for various operating systems. By enabling developers to create desktop apps utilizing web technologies like HTML, CSS, and JavaScript, frameworks like Electron transformed this environment.

Tauri is a lightweight alternative that has surfaced more lately. It promises better speed, reduced memory use, and smaller application sizes while preserving the flexibility to create cross-platform apps using well-known frontend technologies.

In this article, we'll compare Tauri and Electron, explore their architectures, strengths, limitations, and help you decide which framework is best suited for your desktop application projects.

What Is Electron?

Electron is a framework for building desktop applications using web technologies.
Electron combines:

  • Chromium browser engine
  • Node.js runtime

This combination allows developers to create desktop applications using:

  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • Popular frontend frameworks

Many well-known applications are built with Electron, including:

  • Visual Studio Code
  • Slack
  • Postman
  • Discord

Electron's popularity comes largely from its mature ecosystem and developer-friendly tooling.

What Is Tauri?

Tauri is an open-source framework for building desktop applications using web technologies combined with Rust.
Unlike Electron, Tauri does not bundle an entire Chromium browser with every application.

Instead, it uses the operating system's native web rendering engine:

  • WebView2 on Windows
  • WebKit on macOS
  • WebKitGTK on Linux

This architectural decision significantly reduces application size and memory consumption.

Tauri applications typically consist of:

  • Frontend UI
  • Rust backend
  • Native operating system WebView

Architecture Comparison
The biggest difference between Electron and Tauri is their architecture.

Electron Architecture

Desktop App
      ↓
 Chromium
      ↓
  Node.js
      ↓
 Operating System

Every Electron application ships with its own Chromium browser.

Benefits:

  • Consistent rendering
  • Predictable behavior
  • Excellent compatibility

Drawbacks:

  • Larger installation size
  • Higher memory consumption

Tauri Architecture
Desktop App
      ↓
 Native WebView
      ↓
 Rust Backend
      ↓
 Operating System


Because Tauri uses native WebViews, applications are often significantly smaller.

Benefits:

  • Smaller binaries
  • Reduced memory usage
  • Faster startup times

Drawbacks:

  • Dependency on system WebView versions
  • Application Size Comparison

Application size is one of the most discussed differences.

A simple "Hello World" application often results in:

FrameworkTypical App Size
Electron 80 MB - 150 MB
Tauri 5 MB - 20 MB

The exact size varies depending on application complexity and included assets.

For organizations distributing desktop applications at scale, this difference can significantly impact download times and storage requirements.

Performance Comparison

Performance involves several factors.

Startup Time
Tauri generally starts faster because it does not need to initialize a bundled Chromium engine.

Memory Consumption

Electron applications typically consume more RAM because each application includes Chromium processes.

Example:
Electron App
   ↓
 Chromium Process
   ↓
 Renderer Process
   ↓
 Additional Processes

Tauri's lightweight architecture often results in lower resource usage.

Rendering Performance
Both frameworks deliver excellent UI performance when built using modern frontend frameworks.
For most business applications, users may not notice substantial rendering differences.

Development Experience
Both frameworks support modern frontend development workflows.

Popular frontend choices include:

  • React
  • Vue.js
  • Angular
  • Svelte

Electron example:
const { app, BrowserWindow } = require('electron');

function createWindow() {
  const window = new BrowserWindow({
    width: 800,
    height: 600
  });

  window.loadURL('http://localhost:3000');
}

app.whenReady().then(createWindow);


Tauri application setup typically involves frontend code combined with Rust commands.

Example Rust command:
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

Developers unfamiliar with Rust may face a learning curve when adopting Tauri.

Security Considerations
Desktop application security is increasingly important.

Electron security challenges often stem from:

  • Node.js access
  • Browser APIs
  • Misconfigured permissions

Electron applications require careful hardening.

Tauri takes a more restrictive approach.

Security benefits include:

  • Smaller attack surface
  • Fine-grained API permissions
  • Rust memory safety
  • Reduced dependency footprint

For security-sensitive applications, these characteristics can be particularly attractive.

Ecosystem and Community

Electron has been available for much longer.

Advantages include:

  • Large community
  • Extensive documentation
  • Mature plugins
  • Production-proven tooling

Tauri's ecosystem continues to grow rapidly but remains smaller.

Advantages include:

  • Active open-source community
  • Modern architecture
  • Strong focus on performance
  • Increasing enterprise interest

Organizations often consider ecosystem maturity when making framework decisions.
Practical Example

Imagine a company building an internal productivity application.

Requirements:

  • Cross-platform support
  • Modern user interface
  • Frequent updates
  • Minimal resource usage

Possible evaluation:
Electron

Advantages:

  • Faster onboarding
  • Larger ecosystem
  • Familiar JavaScript environment

Challenges:

  • Larger downloads
  • Higher memory usage

Tauri
Advantages:

  • Smaller binaries
  • Better resource efficiency
  • Strong security model

Challenges:

  • Rust learning curve
  • Smaller ecosystem

The best choice depends on the team's priorities and technical expertise.

When to Choose Electron
Electron may be the right choice when:

  • Development speed is a priority.
  • Existing teams are JavaScript-focused.
  • Mature tooling is important.
  • Large plugin ecosystems are required.
  • Cross-platform consistency is critical.

Many organizations successfully use Electron for enterprise-grade desktop applications.

When to Choose Tauri
Tauri may be the better option when:

  1. Application size matters.
  2. Resource efficiency is important.
  3. Security is a major concern.
  4. Teams are comfortable with Rust.
  5. Modern architecture is preferred.

Tauri is particularly attractive for lightweight desktop applications.

Best Practices
Minimize Unnecessary Dependencies
Keep application bundles small and maintainable.

Optimize Frontend Assets

Use code splitting and asset compression to improve startup performance.

Follow Security Guidelines

Restrict permissions and expose only required functionality.

Profile Resource Usage
Monitor:

  • CPU usage
  • Memory consumption
  • Startup time
  • Application size

Use Native Features Carefully
Avoid excessive platform-specific implementations that reduce portability.

Choose Based on Team Expertise

Technical familiarity often has a larger impact on project success than framework differences.

Conclusion

Both Tauri and Electron provide powerful solutions for building cross-platform desktop applications using modern web technologies. Electron offers a mature ecosystem, extensive community support, and a proven track record powering some of the world's most popular desktop applications.

Tauri introduces a modern alternative focused on performance, security, and efficiency. By leveraging native WebViews and Rust, it delivers significantly smaller applications and lower resource consumption while maintaining cross-platform compatibility.

For teams seeking rapid development and maximum ecosystem support, Electron remains an excellent choice. For organizations prioritizing lightweight deployments, enhanced security, and efficient resource usage, Tauri presents a compelling alternative.

Ultimately, the decision between Tauri and Electron depends on your application's requirements, team expertise, and long-term maintenance goals. Both frameworks are capable of delivering high-quality desktop experiences for modern users.



AngularJS Hosting Europe - HostForLIFE :: Using the Google Maps API to Create an Angular Real-Time GPS Tracking Dashboard

clock June 11, 2026 08:22 by author Peter

This article describes how to use Angular, the Google Maps JavaScript API, and real-time push technologies like SignalR or WebSockets to create a comprehensive real-time GPS tracking dashboard. Every diagram has smaller headers and adheres to your desired style.

The information is appropriate for both novice and seasoned full-stack engineers, and the language is maintained simple in Indian English.

Overview

Logistics, taxi services, fleet management, delivery systems, public transportation, and safety applications all make use of real-time GPS tracking. The Google Maps API is the most dependable mapping platform for real-time updates, and Angular offers a great front-end framework for dynamic dashboards.

In this article, we will build a dashboard that:

  • Loads Google Map inside Angular
  • Displays vehicles or assets as markers
  • Updates marker positions in real time
  • Shows movement paths (polyline)
  • Displays speed, direction, and other attributes
  • Uses ASP.NET Core backend + SQL Server for storing location history
  • Uses SignalR/WebSocket to push live updates

Flowchart (smaller header)
+-----------------------+
| GPS Device / Mobile   |
| Sends Location Data   |
+-----------+-----------+
                 |
                 v
+-----------+-----------+
| ASP.NET Core API      |
| Stores Data in SQL    |
| Pushes Live Update    |
+-----------+-----------+
                 |
                 v
+-----------+-----------+
| Angular App (Client)  |
| Google Maps Component |
| Marker Refresh        |
+-----------------------+

Workflow (smaller header)

Device generates latitude, longitude, speed, time.

Backend receives data via REST API or MQTT gateway.

SQL Server stores the raw and processed logs.

Backend broadcasts live changes using SignalR/WebSockets.

Angular receives update and moves marker smoothly on Google Map.

Dashboard displays distance covered, history, and alerts.

Architecture Diagram (Visio-style, smaller header)


                   +--------------------------+
                   |   GPS Device / Mobile    |
                   +-----------+--------------+
                               |
                               v
                  +------------+-------------+
                  |   ASP.NET Core API       |
                  |   (Tracking Controller)  |
                  +------------+-------------+
                               |
            +------------------+------------------+
            |                                     |
            v                                     v
+-----------+-----------+            +-------------+---------------+
|   SQL Server DB       |            |  SignalR Hub / WebSockets   |
| (Location History)    |            | Sends Real-time Updates     |
+-----------+-----------+            +-------------+---------------+
                                                   |
                                                   v
                                   +-----------+------------+
                                   | Angular GPS Dashboard  |
                                   | Google Maps Component  |
                                   +------------------------+


ER Diagram (smaller header)
+---------------------+       +---------------------------+
| Device              | 1 --- * | LocationLog             |
+---------------------+       +---------------------------+
| DeviceId (PK)       |       | LogId (PK)               |
| Name                |       | DeviceId (FK)            |
| Type                |       | Latitude                 |
| Status              |       | Longitude                |
+---------------------+       | Speed                    |
                              | Direction                |
                              | RecordedAt (datetime)    |
                              +--------------------------+

Sequence Diagram (smaller header)

Device → API: Send(lat, long, speed)
API → SQL: Insert location log
API → SignalR Hub: Broadcast update
Hub → Angular: Push new coordinates
Angular → Google Maps: Update marker position
User → Angular: View dashboard and history


Setting Up Google Maps in Angular
Step 1: Load Google Maps API
Add the script with your API key in index.html:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY&libraries=geometry"></script>

Step 2: Create the Map Component
map.component.ts

import { Component, OnInit, NgZone } from '@angular/core';

declare const google: any;

@Component({
  selector: 'app-live-map',
  templateUrl: './live-map.component.html',
  styleUrls: ['./live-map.component.scss']
})
export class LiveMapComponent implements OnInit {

  map: any;
  markers: any = {};

  ngOnInit() {
    this.initMap();
  }

  initMap() {
    this.map = new google.maps.Map(document.getElementById('map'), {
      center: { lat: 19.0760, lng: 72.8777 },
      zoom: 11
    });
  }

  updateMarker(deviceId: string, lat: number, lng: number) {
    if (!this.markers[deviceId]) {
      this.markers[deviceId] = new google.maps.Marker({
        position: { lat, lng },
        map: this.map,
        title: deviceId
      });
    } else {
      this.markers[deviceId].setPosition(new google.maps.LatLng(lat, lng));
    }
  }
}

map.component.html
<div id="map"></div>

map.component.scss

#map {
  width: 100%;
  height: 100vh;
}


Adding Real-Time Tracking with SignalR
Step 1: Install SignalR Client

npm install @microsoft/signalr


Step 2: Connect to ASP.NET Core Hub
import * as signalR from '@microsoft/signalr';

export class LiveMapComponent implements OnInit {

  hub: any;

  ngOnInit() {
    this.initMap();

    this.hub = new signalR.HubConnectionBuilder()
      .withUrl('https://yourapi.com/gpsHub')
      .build();

    this.hub.start().then(() => console.log('Hub connected'));

    this.hub.on('locationUpdated', (data: any) => {
      this.updateMarker(data.deviceId, data.lat, data.lng);
    });
  }
}


Backend: ASP.NET Core SignalR Hub
TrackingHub.cs

public class TrackingHub : Hub
{
    public async Task BroadcastLocation(LocationDto location)
    {
        await Clients.All.SendAsync("locationUpdated", location);
    }
}


Receiving Data and Broadcasting
TrackingController.cs

[ApiController]
[Route("api/tracking")]
public class TrackingController : ControllerBase
{
    private readonly IHubContext<TrackingHub> _hub;

    public TrackingController(IHubContext<TrackingHub> hub)
    {
        _hub = hub;
    }

    [HttpPost("update-location")]
    public async Task<IActionResult> UpdateLocation(LocationDto dto)
    {
        // Save in SQL Server
        // _repository.SaveLocation(dto);

        // Broadcast to clients
        await _hub.Clients.All.SendAsync("locationUpdated", dto);

        return Ok();
    }
}


Building the Dashboard UI

You can enhance your Angular dashboard with:

  • Vehicle list with status
  • Search bar
  • Speed and direction indicators
  • Polyline showing route history
  • Alerts (overspeeding, idle time)
  • Heatmap of frequent stops

Example: Drawing Movement Path
updatePath(deviceId: string, lat: number, lng: number) {
  if (!this.paths[deviceId]) {
    this.paths[deviceId] = new google.maps.Polyline({
      path: [],
      map: this.map,
      strokeColor: '#007bff'
    });
  }

  const path = this.paths[deviceId].getPath();
  path.push(new google.maps.LatLng(lat, lng));
}


SQL Server Storage Strategy

  • Use partitioning for large tables
  • Store raw logs separately from processed logs
  • Create indexes on (DeviceId, RecordedAt)
  • Use archival tables for old tracking data

Example DDL
CREATE TABLE LocationLog (
    LogId INT IDENTITY PRIMARY KEY,
    DeviceId NVARCHAR(50),
    Latitude FLOAT,
    Longitude FLOAT,
    Speed FLOAT,
    Direction FLOAT,
    RecordedAt DATETIME2
);


Performance and Scalability Tips

  • Use clustering + SignalR backplane for many devices
  • Use SQL Server temporal tables for fast history browsing
  • Implement marker clustering on Google Maps for large datasets
  • Enable lazy loading of historical paths
  • Use RxJS for throttling UI updates

Conclusion
You now have a complete blueprint for designing and implementing a real-time GPS tracking dashboard in Angular using Google Maps, ASP.NET Core, SignalR, and SQL Server.
The same architecture works for:

  • Fleet tracking systems
  • Cab/driver live monitoring
  • School bus tracking
  • Asset movement inside warehouse
  • Delivery agent tracking


AngularJS Hosting Europe - HostForLIFE :: How to Utilize Angular Forms (Reactive vs. Template-Driven)?

clock June 9, 2026 10:57 by author Peter

Forms are an essential part of most applications. Whether you are building a login screen, registration form, profile update, or payment form, collecting user input correctly and validating it matters.

Angular provides two powerful approaches to manage forms:

  • Template-Driven Forms
  • Reactive Forms

Both allow you to capture input, apply validation, display errors, and submit data. But they are designed for different use cases.

Real-World Scenario
Imagine you are building a small user onboarding module in an Angular application. The flow includes:

  • A simple newsletter signup (just name + email)
  • A detailed user registration form (address, phone number, nested objects, custom validations)

For the small signup form, using Template-Driven makes more sense because it is quick and requires less code.

For the detailed registration form with multiple validations and conditions, Reactive Forms are a better choice because they offer more structure and control.

Approach 1: Template-Driven Forms
Template-Driven Forms are easier to start with and heavily rely on the HTML template. Suitable for smaller and simpler forms.

Step 1: Import FormsModule
In app.module.ts:
import { FormsModule } from '@angular/forms';

@NgModule({
  imports: [BrowserModule, FormsModule],
})
export class AppModule {}

Step 2: Create Component
export class SignupComponent {
  user = {
    name: '',
    email: ''
  };

  submitForm() {
    console.log(this.user);
  }
}


Step 3: Create Form Template
<form #signupForm="ngForm" (ngSubmit)="submitForm()">
  <label>Name:</label>
  <input type="text" name="name" [(ngModel)]="user.name" required />

  <label>Email:</label>
  <input type="email" name="email" [(ngModel)]="user.email" required />

  <button type="submit" [disabled]="signupForm.invalid">Submit</button>
</form>


How Validation Works
Angular automatically tracks:

  • Valid
  • Invalid
  • Touched
  • Dirty

Example validation state
<p *ngIf="signupForm.controls['email']?.invalid && signupForm.controls['email']?.touched">
  Email is required.
</p>


When to Use Template-Driven Forms
Use when:

  • Form is simple
  • Few validations
  • Faster development required
  • No dynamic form generation needed

Example use cases

  • Contact forms
  • Newsletter signup
  • Feedback form

Approach 2: Reactive Forms
Reactive Forms move responsibility to TypeScript. They offer more control, scalability, and testability.

Perfect for:

  • Complex validation
  • Conditional fields
  • Dynamic forms
  • Enterprise applications

Step 1: Import ReactiveFormsModule
In app.module.ts:
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [BrowserModule, ReactiveFormsModule],
})
export class AppModule {}


Step 2: Create Component with FormGroup
import { FormGroup, FormControl, Validators } from '@angular/forms';

export class RegisterComponent {
  registerForm = new FormGroup({
    fullName: new FormControl('', Validators.required),
    email: new FormControl('', [Validators.required, Validators.email]),
    phone: new FormControl('', Validators.required)
  });

  submitForm() {
    console.log(this.registerForm.value);
  }
}


Step 3: Create Template
<form [formGroup]="registerForm" (ngSubmit)="submitForm()">

  <label>Full Name:</label>
  <input type="text" formControlName="fullName" />
  <span *ngIf="registerForm.get('fullName')?.invalid && registerForm.get('fullName')?.touched">
    Name is required.
  </span>

  <label>Email:</label>
  <input type="email" formControlName="email" />
  <span *ngIf="registerForm.get('email')?.invalid && registerForm.get('email')?.touched">
    Enter valid email.
  </span>

  <label>Phone:</label>
  <input type="tel" formControlName="phone" />

  <button type="submit" [disabled]="registerForm.invalid">Register</button>
</form>

Workflow Diagram

User Input
    |
    V
Form Controls Track State
    |
    +--> Apply Validation Rules
    |
    +--> Update UI Error messages
    |
Form Submission

Comparison Summary

FeatureTemplate-DrivenReactive

Setup

Easy

More Setup

Where logic lives

Mostly Template

Mostly TypeScript

Validation

Simple

Advanced

Scalability

Low

High

Dynamic fields

Hard

Easy

Best for

Small apps

Enterprise apps

Common Mistakes and Fixes

MistakeWhy it HappensFix

Form values not updating

Missing ngModel

Add two-way binding

Validation not working

Wrong form control binding

Ensure formControlName matches

Submit button not disabling

Not checking form.invalid

Use [disabled]="form.invalid"

Conclusion
One of the most popular aspects of Angular applications is forms. Understanding both reactive and template-driven forms allows you options based on the complexity and scale. Simple and rapid creation are the main goals of template-driven forms. Reactive Forms provide scalability, testability, and structure. Reactive Forms will soon become the norm if you keep developing massive applications.



AngularJS Hosting Europe - HostForLIFE :: Difference Between LRU Cache and LFU Cache

clock May 25, 2026 10:59 by author Peter

Different methods are used in computer science, specifically in the management of cache memory, to decide which objects to discard when the cache is full. LRU (Least Recently Used) and LFU (Least Frequently Used) are two of the most used algorithms. Optimizing cache performance in a variety of applications requires an understanding of the distinctions between these two techniques.

What is LRU Cache?
The LRU (Least Recently Used) cache algorithm is designed to the discard the least recently accessed items first. The idea behind LRU is that items that have not been accessed recently are less likely to be accessed in the near future making them prime candidates for the removal when the cache becomes full.

Characteristics

  • Recency-Based: The LRU focuses on how recently an item was accessed.
  • Eviction Policy: When the cache is full, the item that has not been used for the longest period of the time is removed.
  • Implementation: Typically implemented using the doubly linked list and a hash map for the O(1) access and eviction times.
  • Predictability: It is easy to the predict which items will be evicted.

Applications

  • Web Browsers: To store recently accessed web pages.
  • Operating Systems: In memory management to the maintain pages in the physical memory.
  • Databases: For caching query results to the improve performance.

What is LFU Cache?
The LFU (Least Frequently Used) cache algorithm discards the least frequently accessed the items first. The rationale behind LFU is that items that are accessed less frequently are less likely to be accessed again in the future.

Characteristics

  • Frequency-Based: The LFU focuses on how frequently an item was accessed.
  • Eviction Policy: When the cache is full the item with lowest access frequency is removed.
  • Implementation: Can be implemented using the min-heap and a hash map to keep track of the frequencies and ensure O(log n) eviction time.
  • Adaptability: Can adapt to the changing access patterns over time but may require more complex data structures.

Applications

  • Content Delivery Networks (CDNs): To cache frequently accessed content for the quicker delivery.
  • Databases: For maintaining frequently accessed records in the memory.
  • Mobile Applications: To store frequently used data to the reduce loading times.

Difference Between LRU Cache and LFU Cache:

CharacteristicsLRU CacheLFU Cache
Basis Recency of Access Frequency of Access
Eviction Policy The Removes least recently accessed item The Removes least frequently accessed item
Implementation Complexity Relatively Simple More Complex
Data Structures Used Doubly Linked List + Hash Map Min-Heap + Hash Map
Access Time O(1) O(1) for access O(log n) for the eviction
Use Case Suitability The Suitable for scenarios with the strong temporal locality The Suitable for scenarios with the skewed access frequencies
Predictability High Lower due to the frequency tracking
Adaptability The Less adaptable to the changing patterns More adaptable over time
Applications Web Browsers, OS Memory Management, Databases CDNs, Databases, Mobile Apps

Conclusion

Both the LRU and LFU cache algorithms have special advantages and work well for a variety of applications. The LRU is simple to use and performs well in settings where it is expected that the most recent data will be accessed again. However, even though LFU is more difficult to implement, it works better in situations when certain things are accessed frequently over extended periods of time. The particular requirements of the application and its access patterns determine which cache eviction policy is best.



AngularJS Hosting Europe - HostForLIFE :: Knowing Angular Standalone Components (with a Real-Time Store Application)

clock April 23, 2026 09:23 by author Peter

The addition of Standalone Components has been one of the most significant advancements in Angular's evolution over the years. By decreasing boilerplate and increasing the self-containedness and reusability of components, this feature streamlines application architecture.

Using a real-time shop application sample that I created locally, I will describe independent components, how they differ from ordinary (module-based) components, and when not to use them.

What is a Standalone Component?
A Standalone Component is an Angular component that does not need to be declared inside an NgModule.

Instead of relying on modules for declarations and imports, a standalone component directly manages its own dependencies.

In traditional Angular applications:

  1. Every component must be declared in an NgModule
  2. Routing, directives, and pipes are imported via modules

With standalone components:

  • Components are self-contained
  • Dependencies like CommonModule, RouterLink, or other components are imported directly in the component decorator
  • Applications become simpler, more readable, and easier to maintain

Angular now recommends standalone components for new applications, making them the future-proof approach.

Real-Time Scenario: Store Application Using Standalone Components
To understand standalone components in practice, I created a simple store application with the following pages:

  • Landing Page
  • Products Page
  • Product Details Page
  • Services Page
  • About Us Page
  • Contact Us Page

Almost all components in this application are standalone, including routing and navigation.

Routing Without Modules (app.routes.ts)
Instead of defining routes inside a routing module, routes are configured directly using standalone components:
export const routes: Routes = [
  { path: '', component: LandingComponent },
  { path: 'about', component: AboutComponent },
  { path: 'products', component: ProductListComponent },
  { path: 'products/:id', component: ProductDetailComponent },
  { path: 'services', component: ServicesComponent },
  {
    path: 'contact',
    loadComponent: () =>
      import('./contact/contact.component').then(m => m.ContactComponent)
  },
];


Why this matters

  • No routing module required
  • Supports lazy loading at component level
  • Cleaner and more readable route definitions

Root Component as a Standalone Component
The root component (AppComponent) itself is standalone and imports only what it needs:
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, NavbarComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  title = 'Standalone_Component_POC';
}

Key Takeaways

RouterOutlet and NavbarComponent are imported directly
No AppModule is required
The root component controls its own dependencies

Navbar as a Reusable Standalone Component
The navigation bar is a perfect example of a reusable standalone component:
@Component({
  selector: 'app-navbar',
  standalone: true,
  imports: [RouterLink, RouterLinkActive],
  templateUrl: './navbar.component.html',
})
export class NavbarComponent {}


Benefits

  • Can be reused across multiple pages
  • No shared module needed
  • Easy to move or refactor

Product Listing Page Using Standalone Component
The products page displays a list of products and uses routing for navigation:
@Component({
  selector: 'app-product-list',
  standalone: true,
  imports: [CommonModule, RouterLink],
  templateUrl: './product-list.component.html'
})
export class ProductListComponent {
  products = [
    { id: 1, name: 'Red T-Shirt', price: 19.99 },
    { id: 2, name: 'Blue Jeans', price: 49.99 },
    { id: 3, name: 'Sneakers', price: 89.99 },
  ];
}


What this demonstrates
CommonModule is imported directly for structural directives
RouterLink is imported at component level
The component is fully independent and reusable

Lazy-Loaded Contact Page
The Contact page is lazy-loaded using loadComponent, which avoids loading it upfront:
@Component({
  selector: 'app-contact',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './contact.component.html',
})
export class ContactComponent {}


Why this is powerful

  • Reduces initial bundle size
  • Improves application performance
  • No feature module required for lazy loading

UI Screenshots of the Store Application Built Using Standalone Components
Landing Page – Standalone Component Entry Point

Key Highlights

  • Loaded directly via router configuration
  • No module dependency
  • Clean and lightweight setup

Products Page – Standalone Component with Routing

Key Highlights:

  • Uses *ngFor from CommonModule
  • Navigates using RouterLink
  • Demonstrates data display in a standalone component

Contact Us Page – Lazy Loaded Standalone Component

Key Highlights:

  • Lazy-loaded at component level

  • No feature module required

  • Improves performance and scalability

Regular Component vs Standalone Component

FeatureRegular ComponentStandalone Component
Requires NgModule Yes No
Boilerplate code High Minimal
Lazy loading Module-based Component-based
Dependency handling Via modules Inside component
Reusability Limited High
Recommended for new apps No Yes

When NOT to Use Standalone Components

Although standalone components are highly recommended, there are a few scenarios where they might not be ideal:

  • Large legacy applications heavily dependent on modules
  • Applications running on older Angular versions
  • Complex shared module patterns that are expensive to refactor
  • Teams not ready to migrate existing module-based architecture

For new projects and modern Angular versions, standalone components should be the default choice.



AngularJS Hosting Europe - HostForLIFE :: Managing Multiple Tenancy in Angular Applications

clock March 13, 2026 07:47 by author Peter

A common architectural technique in SaaS applications is multi-tenancy, in which a single application instance serves several clients (tenants). Individual setups, separated data, and even customized themes or domain settings are all maintained by each tenant. To achieve appropriate isolation and flexibility, multi-tenancy implementation in Angular apps necessitates careful design in areas like routing, state management, authentication, and user interface customisation.

Overview of Multi-Tenancy Architecture
The entire tenant-aware request lifecycle in an Angular-based SaaS application is depicted in the following diagram. It demonstrates how a single Angular application can dynamically adjust to several tenants while upholding stringent backend data separation.

Browser (Angular Application)
The Angular application loads in the browser as a single shared codebase for all tenants. During initialization, it prepares core services and starts resolving tenant context. At this stage, the app is generic and not yet tenant-aware.

Tenant Identification
The application identifies the tenant using subdomain, route parameter, or authentication token. This step determines which organization is accessing the system. Without successful tenant resolution, the app should not proceed further.

Load Tenant Configuration
After identifying the tenant, the app fetches tenant-specific settings such as theme, language, and feature flags. This configuration is typically loaded before the UI renders. Once completed, the application becomes tenant-aware.

API Calls with Tenant ID
All outgoing HTTP requests include the Tenant ID, usually via an interceptor or token. This ensures every request is scoped correctly. The backend can now recognize which tenant is making the request.

Backend Filters Data Per Tenant
The backend validates the tenant and applies filters to database queries. This guarantees strict data isolation between tenants. True security enforcement always happens on the server side.

Tenant Identification Strategies
The first and most important stage in a multi-tenant Angular application is tenant identification. It chooses which organization's setup, branding, and data to be loaded. To guarantee that the application initializes with the correct tenant context, this identification must take place early in the application lifecycle.

Common strategies include:

  • Subdomain-based identification (e.g., tenant1.myapp.com), which is widely used in SaaS platforms.
  • URL-based (path based) identification (e.g., /tenant1/dashboard), suitable for shared domains.
  • Token-based identification, where the tenant information is embedded in the JWT after login.

Choosing the right strategy depends on your infrastructure, domain setup, and security model, but the goal remains the same — reliably resolve the tenant before loading tenant-specific resources.

Comparison of Approaches

ApproachExampleAdvantagesLimitationsBest Use Case

Subdomain-Based

tenant1.myapp.com

Clear tenant separation, scalable for SaaS, supports custom domains

Requires DNS & SSL setup per tenant

Large-scale SaaS platforms

URL-Based

myapp.com/tenant1

Easy to implement, no extra DNS configuration, simple routing

Less clean branding, weaker logical separation

Small to mid-scale applications

Token-Based

Tenant resolved from JWT after login

Secure, backend-controlled, works well with role-based systems

Tenant unknown before login, not ideal for public tenant pages

Enterprise or authentication-driven systems

Challenges & Best Practices

  • Data Security: Enforce strict tenant isolation on the backend. The frontend should never depend solely on client-side validations to protect tenant data.
  • Scalability: Implement lazy loading so tenant-specific modules are loaded only when required, preventing unnecessary increase in bundle size.
  • Maintainability: Place common logic in shared or core modules, and separate tenant-specific functionality into dedicated modules for better structure and clarity.
  • Testing: Create automated test cases that cover multiple tenant scenarios to ensure changes do not introduce cross-tenant issues or regressions.

Creating a Tenant Service
In a multi-tenant Angular application, tenant information (such as Tenant ID, theme, language, and feature flags) must be accessible across the entire application. Creating a Tenant Service provides a centralized place to store and manage this tenant context.

Without a dedicated service, tenant-related logic would be scattered across components, guards, and interceptors, making the application difficult to maintain and prone to errors. A Tenant Service ensures a single source of truth for tenant data.

It also enables:

  • Easy access to tenant information in HTTP interceptors
  • Dynamic theming and language switching
  • Route guards that validate tenant availability
  • Reactive updates when tenant configuration changes

@Injectable({ providedIn: 'root' })
export class TenantService {
  private tenantConfig = signal<any>(null);

  setTenant(config: any) {
    this.tenantConfig.set(config);
  }

  getTenant() {
    return this.tenantConfig();
  }
}


Load Tenant Configuration at App Startup

Loading tenant configuration at application startup ensures the Angular app initializes with the correct tenant context before rendering any UI. Since tenant-specific settings (such as theme, language, feature flags, and permissions) directly affect how the application behaves, they must be available from the very beginning.

If the configuration is loaded after the app renders, users may experience issues like incorrect theming, wrong language display, or temporary access to features that should be restricted. This can lead to inconsistent behavior and a poor user experience.

To avoid this, Angular provides mechanisms like APP_INITIALIZER, which delay application bootstrap until tenant configuration is fetched from the backend. This guarantees that the app becomes fully tenant-aware before components and routes are activated.
//Use APP_INITIALIZER
export function loadTenantConfig(tenantService: TenantService) {
  return () => tenantService.initialize();
}

//app.config.ts

providers: [
  {
    provide: APP_INITIALIZER,
    useFactory: loadTenantConfig,
    deps: [TenantService],
    multi: true
  }
]


Passing Tenant ID in HTTP Requests

In a multi-tenant application, every API request must clearly indicate which tenant is making the request. Passing the Tenant ID in HTTP requests ensures that the backend can correctly scope data access and apply tenant-specific filters.

This is typically implemented using an HTTP interceptor in Angular. The interceptor automatically attaches the Tenant ID to outgoing requests, usually as a custom header (e.g., X-Tenant-ID) or through JWT claims. This keeps the implementation centralized and avoids repeating logic in every service call.

By including the Tenant ID in each request, the backend can enforce proper data isolation and prevent cross-tenant data access. However, it’s important to remember that the server must always validate the tenant identity rather than blindly trusting client-provided values.
@Injectable()
export class TenantInterceptor implements HttpInterceptor {
  constructor(private tenantService: TenantService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const tenantId = this.tenantService.getTenant()?.id;

    const modifiedReq = req.clone({
      setHeaders: {
        'X-Tenant-ID': tenantId
      }
    });

    return next.handle(modifiedReq);
  }
}

Route Guards for Tenant Validation
In a multi-tenant Angular application, route guards ensure that navigation only occurs when a valid tenant context is available. Before allowing access to protected routes (such as dashboard or feature modules), the application must confirm that the tenant has been correctly identified and loaded.

Using a route guard in Angular allows you to validate conditions like:

  • Tenant configuration is successfully loaded
  • Tenant ID exists and is valid
  • Required permissions are available

If validation fails, the guard can redirect the user to an error page, login screen, or tenant selection page. This prevents unauthorized or incomplete access to the application.
@Injectable({ providedIn: 'root' })
export class TenantGuard implements CanActivate {
  constructor(private tenantService: TenantService) {}

  canActivate(): boolean {
    return !!this.tenantService.getTenant();
  }
}

Apply to routes:
{
  path: 'dashboard',
  canActivate: [TenantGuard],
  loadComponent: () => import('./dashboard.component')
}


Lazy Loading with Tenant Context
Lazy loading is commonly used in Angular applications to improve performance by loading feature modules only when needed. In a multi-tenant setup, it is important that tenant context is already established before any lazy-loaded module initializes.

If tenant configuration is not loaded first, lazy modules may attempt to fetch data or apply logic without knowing the correct Tenant ID. This can result in incorrect API calls, broken theming, or inconsistent permissions.

To avoid this, tenant resolution and configuration loading should occur at the root level (during app startup). Lazy-loaded modules should simply consume the existing tenant context from a centralized Tenant Service rather than re-fetching or recalculating it.

Security Considerations (Very Important)
The most important component of the architecture in a multi-tenant application is security. Real data separation must never be enforced by the frontend (such as Angular), even when it controls tenant context for UI customisation and routing.

The backend must always apply stringent tenant-based filtering to all database queries and verify the tenant's identification from a reliable source, like JWT claims. Because headers are manipulable, it should never rely exclusively on a client-provided header like X-Tenant-ID.

Proper security implementation should include:

  • Server-side tenant validation
  • Database-level tenant filtering
  • Protection against cross-tenant data access
  • Clearing cached or stored data on logout
  • Common Mistakes in Multi-Tenant Angular Applications

Here are key mistakes developers often make when implementing multi-tenancy:

  • Resolving tenant too late – Loading tenant configuration after modules initialize can cause incorrect API calls or UI flickering.
  • Duplicating tenant logic across components – Tenant checks scattered in multiple components create tight coupling and poor maintainability.
  • Not resetting state on tenant switch – Failing to clear in-memory state (store, signals, caches) can expose previous tenant data.
  • Caching API responses globally – Shared caches without tenant scoping may return data from another tenant.
  • Hardcoding tenant-based conditions – Writing if (tenantId === 'tenant1') inside components leads to unscalable code.
  • Ignoring permission differences per tenant – Assuming all tenants have the same roles and features reduces flexibility.
  • Not handling invalid tenants gracefully – Missing fallback or error handling when a tenant does not exist results in broken UX.
  • Trusting frontend validation for security – Relying only on Angular checks without backend enforcement can cause serious data breaches.
  • Over-fetching tenant configuration – Repeatedly calling the tenant config API instead of centralizing it impacts performance.
  • Mixing environment configuration with tenant configuration – Environment settings (API URLs, production flags) should not be confused with tenant-specific runtime settings.

Conclusion
Managing multi-tenancy in an Angular application necessitates a well-structured architecture where tenant identification, configuration loading, request scoping, and security enforcement all operate together flawlessly. This goes beyond simply giving a Tenant ID in API calls. You build a consistent and scalable foundation by resolving the tenant early, centralizing tenant context in a dedicated service, loading configuration at startup, and making sure all HTTP requests convey correct tenancy information. This strategy enables a single Angular codebase to securely serve numerous tenants without sacrificing security or performance when combined with backend-enforced data segregation. When multi-tenancy is properly handled, you can create robust SaaS apps that are safe, scalable, and adaptable as your clientele expands.



AngularJS Hosting Europe - HostForLIFE :: Using OnPush Change Detection to Optimize Angular Performance

clock March 5, 2026 06:27 by author Peter

One of the most crucial aspects of contemporary online apps is performance. The way the framework manages updates becomes crucial as Angular projects grow in size and complexity, particularly large enterprise apps with dashboards, forms, and real-time data. Effective change detection guarantees that the application remains responsive and quick. Slower screens and a bad user experience might result from poorly handled delays, even minor ones. For Angular apps to remain dependable and seamless, change detection optimization is essential.

Comprehending Angular Change Detection
To maintain the user interface (DOM) in sync with the application's data, Angular employs a mechanism known as Change Detection. Angular uses change detection to determine whether the view needs to be updated whenever something in the application changes, such as a user clicking a button, getting an HTTP response, or a timer going off.

  1. Angular uses the ChangeDetectionStrategy by default.default configuration. Using this method:
  2. During each cycle of change detection, every component in the application is examined.
  3. Every event, regardless of size, initiates a comprehensive check throughout the whole component tree.

This default behavior works well for small and medium-sized applications since it is straightforward and dependable. However, it can become ineffective in large systems with intricate user interfaces, including enterprise programs with numerous nested components, dashboards, and real-time data streams. Performance can be slowed down by running change detection everywhere for every event, which results in sluggish interactions and wasted processing resources.

Because of this, developers frequently search for ways to optimize change detection so that Angular only modifies the areas of the application that truly require it.

OnPush Change Detection Strategy
When you switch to ChangeDetectionStrategy.OnPush, Angular becomes more selective. Instead of checking every component on every cycle, Angular re-evaluates a component only when specific conditions are met:

  • Input reference changes – Angular checks the component if one of its @Input() properties receives a new reference (not just a mutated object).
  • Events triggered within the component – If a user interaction (like a click) occurs in the component or one of its children, Angular runs change detection for that subtree.
  • Observable or Signal updates – When data streams (via Observable, async pipe) or Angular Signals emit new values, the component updates accordingly.
  • Manual triggering using ChangeDetectorRef –
    • markForCheck() tells Angular to include the component in the next change detection cycle.
    • detectChanges() immediately runs change detection for the component and its subtree.

Default vs OnPush – Key Differences

FeatureDefault (Eager)OnPush

Change detection trigger

Any event

Input reference change

Performance

Moderate

High

Suitable for

Small apps

Large & scalable apps

Manual control

Rarely needed

Often needed

How to Use OnPush?
To enable the OnPush strategy, configure the changeDetection property inside your component decorator. This tells Angular to run change detection for the component only when specific triggers occur (such as input reference changes, events, or observable emissions), improving performance by avoiding unnecessary checks.
import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
  selector: 'app-user-card',
  templateUrl: './user-card.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserCardComponent {
  @Input() user!: User;
}


With this setup, Angular will skip checking UserCardComponent unless its @Input() reference changes or another valid OnPush trigger occurs.

Why OnPush Improves Performance?

Angular’s default change detection strategy is ChangeDetectionStrategy.Default. With this approach:

  • Angular traverses the entire component tree during every change detection cycle.
  • It checks all bindings, even if the underlying data hasn’t changed.
  • Any event—such as a click, an HTTP response, or a timer—triggers change detection across the whole application.

This works fine for smaller apps, but in large-scale applications with complex UIs, it can quickly become inefficient. The repeated checks consume unnecessary CPU cycles and lead to more DOM updates than needed, which can slow down performance.

By contrast, ChangeDetectionStrategy.OnPush changes the way Angular decides when to update a component:

  • Angular skips checking a component unless its input properties change or an observable emits new data.
  • This reduces the number of components Angular needs to process, lowering CPU usage.
  • It minimizes DOM updates, ensuring only the parts of the UI that actually need refreshing are updated.
  • As a result, applications become more scalable and responsive, even under heavy workloads.

OnPush is especially beneficial in scenarios such as:

  • Data-heavy dashboards with multiple widgets and charts.
  • Large tables with thousands of rows where frequent updates would otherwise be costly.
  • Real-time applications that continuously receive new data streams.
  • Enterprise Angular apps with deeply nested component structures and complex state management.

Important Concept: Immutability
OnPush works best when you use immutable data. This means you don’t directly change existing objects; instead, you create a new one when something changes.

Wrong Way (Mutation)
// Mutating the existing object
this.user.name = 'John';


Angular will not detect this change because the object reference remains the same.

Correct Way (New Reference)
// Creating a new object reference
this.user = {
  ...this.user,
  name: 'John'
};

Here, Angular detects the change because the object reference is new. By following immutability, Angular’s OnPush strategy can correctly identify updates, making apps more predictable, easier to debug, and more efficient—especially in large-scale applications.

Using OnPush with Observables

When working with OnPush change detection, one of the best practices is to use the async pipe in your templates.
<!-- Using async pipe with OnPush -->
<div *ngIf="user$ | async as user">
  {{ user.name }}
</div>


Why this works well:

  • The async pipe automatically subscribes to the observable and unsubscribes when the component is destroyed, preventing memory leaks.
  • It marks the component for check whenever new data is emitted, ensuring Angular updates the view correctly under OnPush.
  • It keeps the code clean and declarative, avoiding manual subscription management in the component class.
  • It fits perfectly with immutable data patterns, since each new emission creates a fresh reference that OnPush can detect.

Manual Change Detection (Advanced)
Even with OnPush, there are scenarios where Angular will not automatically detect changes—especially when updates occur outside Angular’s normal triggers (e.g., setTimeout, third-party libraries, manual DOM events, or non-reactive data updates).

In such cases, you can take manual control using ChangeDetectorRef.

Using markForCheck()
markForCheck() tells Angular: " This component should be checked in the next change detection cycle. "

It does not trigger detection immediately. Instead, it schedules the component to be checked when Angular runs the next cycle.
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';

@Component({
  selector: 'app-user-card',
  template: `{{ data }}`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserCardComponent {
  data = '';

  constructor(private cd: ChangeDetectorRef) {}

  updateData(newValue: string) {
    this.data = newValue;
    this.cd.markForCheck(); // Schedule check for next cycle
  }
}


Best used when:

  • Updating state asynchronously
  • Integrating with third-party libraries
  • Updating data outside Angular’s zone

Using detectChanges()
detectChanges() runs change detection immediately for the component and its subtree.
this.cd.detectChanges(); // Immediately updates the view

This is more aggressive because it forces Angular to re-evaluate the component instantly.

Best used when:

  • You need immediate UI refresh
  • You're inside callbacks where Angular won't trigger detection
  • You detached change detection and want to manually control execution

Overusing markForCheck() or detectChanges() can defeat the purpose of OnPush by reintroducing frequent checks.

Manual change detection should be:

  • A targeted solution, not a default pattern
  • Used only when reactive patterns (Observables, Signals, immutable inputs) are not sufficient

Conclusion
The strategy for change detection.One of Angular's best performance-enhancing technologies is OnPush. It encourages an immutable architecture, enhances scalability, and minimizes pointless tests. Additionally, OnPush easily integrates with Signals and Observables, increasing the effectiveness of reactive patterns. Gaining proficiency with OnPush is essential for developers constructing enterprise-grade applications in order to produce Angular apps that are quick, responsive, and manageable.



AngularJS Hosting Europe - HostForLIFE :: What is Exhaust? An Example of an Angular Map?

clock February 26, 2026 07:05 by author Peter

Knowing how to use exhaustMap in Angular (RxJS)
The exhaustMap operation in Angular (with RxJS) maps values from a source observable into inner observables; however, it disregards fresh emissions while the preceding inner observable is still operating.

It is frequently used when preventing duplicate requests during button clicks, login requests, and form submissions.

Angular makes extensive use of the RxJS library for reactive programming, which is where exhaustMap originates.

How exhaustMap Works
When the source Observable emits a value:
It creates an inner Observable.

While that inner Observable is active:

  • Any new emissions from the source are ignored.

Once the inner Observable completes:

  • It can accept the next source emission.

Simple Example (Concept)
Imagine a Login button:

  • User clicks once → API call starts.
  • User clicks again quickly → ignored.
  • API completes → next click will work.

This prevents multiple API calls.
source$.pipe(
exhaustMap(value => innerObservable$)
);

Angular Example (Login Button)
Component Example
import { Component } from '@angular/core';
import { fromEvent } from 'rxjs';
import { exhaustMap } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-login',
  template: `<button #loginBtn>Login</button>`
})
export class LoginComponent {

  constructor(private http: HttpClient) {}

  ngAfterViewInit() {
    const button = document.querySelector('button');

    fromEvent(button!, 'click')
      .pipe(
        exhaustMap(() =>
          this.http.post('https://api.example.com/login', {
            username: 'test',
            password: '123'
          })
        )
      )
      .subscribe(response => {
        console.log('Login success', response);
      });
  }
}

What Happens Here?
First click → HTTP request starts.
Second click (before request finishes) → ignored.
After request completes → next click works.

Difference from Other Operators

OperatorBehavior
mergeMap Allows multiple inner Observables simultaneously
switchMap Cancels previous inner Observable
concatMap Queues them one by one
exhaustMap Ignores new ones until current completes

When to Use exhaustMap

✔ Login button
✔ Submit form
✔ Prevent duplicate API calls
✔ Prevent double payments

❌ When you need cancellation → use switchMap
❌ When you need queuing → use concatMap

Real-World Use Case (Form Submit in Angular)
this.formSubmit$
  .pipe(
    exhaustMap(formValue => this.apiService.saveData(formValue))
  )
  .subscribe();

If the user clicks submit multiple times rapidly:

  • Only the first request runs.
  • Others are ignored until it completes.

Easy Way to Remember
exhaustMap = "Ignore until done."



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in