Full Trust European Hosting

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

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

clock March 13, 2026 08:11 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.

By default, Angular applies the ChangeDetectionStrategy.Default setting. With this approach:

  • Every component in the application is checked during each change detection cycle.
  • Any event, no matter how small, triggers a full check across the entire component tree.

This default behavior is simple and reliable, which makes it great for small or medium-sized applications. However, in large applications with complex user interfaces—such as enterprise apps with many nested components, dashboards, and real-time data streams—it can become inefficient. Running change detection everywhere for every event can slow down performance, leading to laggy interactions and wasted processing power.

That’s why developers often look for ways to optimize change detection, so Angular only updates the parts of the app that actually need 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
Set up the changeDetection property in your component decorator to activate the OnPush approach. This improves speed by preventing needless checks by instructing Angular to execute change detection for the component only in response to particular triggers (such as input reference changes, events, or observable emissions).

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 :: BehaviorSubject vs Signals in Angular

clock March 5, 2026 06:56 by author Peter

In modern Angular (v16+), developers now have two powerful reactive tools

  • BehaviorSubject from RxJS
  • Signals, introduced natively in Angular 16

Both manage state - but they are built for different problems.

This article explains:

  • The conceptual difference
  • A real-world example (E-commerce Cart)
  • Performance implications
  • A modern hybrid solution (best practice in 2026)
Conceptual Difference
BehaviorSubject


A BehaviorSubject is:
  • A special type of Observable
  • Requires an initial value
  • Emits the latest value to new subscribers
  • Push-based stream
  • Designed for async flows
It’s ideal for:
  • HTTP responses
  • WebSocket data
  • Complex async transformations
  • Event streams
Signal
A Signal is:
  • A reactive value container
  • Pull-based
  • No subscription needed
  • Automatically tracked by Angular
  • Fine-grained reactive updates
It’s ideal for:
  • UI state
  • Derived state
  • Component state
  • Performance-sensitive rendering
  • Real-Time Example: E-Commerce Cart
Let’s imagine:
  • User adds products to cart
  • Cart total updates instantly
  • Products are loaded from API
  • UI must update efficiently
Version 1: Using BehaviorSubject (Classic Angular)
cart.service.ts
@Injectable({ providedIn: 'root' })
export class CartService {

  private cartSubject = new BehaviorSubject<Product[]>([]);
  cart$ = this.cartSubject.asObservable();

  addToCart(product: Product) {
    const current = this.cartSubject.value;
    this.cartSubject.next([...current, product]);
  }

  getTotal(): number {
    return this.cartSubject.value.reduce((sum, p) => sum + p.price, 0);
  }
}


cart.component.ts
export class CartComponent implements OnInit, OnDestroy {
  cart: Product[] = [];
  total = 0;
  sub!: Subscription;

  constructor(private cartService: CartService) {}

  ngOnInit() {
    this.sub = this.cartService.cart$.subscribe(cart => {
      this.cart = cart;
      this.total = cart.reduce((s, p) => s + p.price, 0);
    });
  }

  ngOnDestroy() {
    this.sub.unsubscribe();
  }
}


Problems
  • Manuals subscribe/unsubscribe
  • Boilerplate
  • Whole component re-evaluates
  • Not fine-grained
  • Easy to create memory leaks
Version 2: Using Signals (Modern Angular)
cart.service.ts
@Injectable({ providedIn: 'root' })
export class CartService {

  cart = signal<Product[]>([]);

  total = computed(() =>
    this.cart().reduce((sum, p) => sum + p.price, 0)
  );

  addToCart(product: Product) {
    this.cart.update(items => [...items, product]);
  }
}


cart.component.ts
export class CartComponent {
  constructor(public cartService: CartService) {}
}

cart.component.html
<div *ngFor="let item of cartService.cart()">
  {{ item.name }} - {{ item.price }}
</div>

<h3>Total: {{ cartService.total() }}</h3>


Why Signals Win Here?
  • No subscriptions
  • No memory leak risk
  • Computed total auto-updates
  • Only total re-renders when cart changes
  • Less code
  • Better performance

Performance Comparison

FeatureBehaviorSubjectSignal
Change detection Zone-based Fine-grained
Subscription overhead Yes No
Memory leaks risk Yes No
Rendering optimization Limited Precise
Boilerplate High Low

Important

BehaviorSubject triggers:
  • Emission → Subscription → Change detection

Signals trigger:
  • Dependency tracking → Only affected bindings re-render
This makes Signals significantly more efficient for UI state.

But Signals Are NOT a Replacement for RxJS
Now let’s extend our cart example.

Products come from API:
this.http.get<Product[]>('/api/products')

We may need:
  • switchMap
  • debounceTime
  • retry
  • catchError
Signals cannot replace RxJS operators.

This is where hybrid architecture shines.

Hybrid Solution (Modern Best Practice)

Use:
  • RxJS for async streams
  • Signals for UI state
Example Hybrid Cart Service
@Injectable({ providedIn: 'root' })
export class CartService {

  // RxJS for API stream
  private products$ = this.http.get<Product[]>('/api/products');

  // Convert observable to signal
  products = toSignal(this.products$, { initialValue: [] });

  // UI state as signal
  cart = signal<Product[]>([]);

  total = computed(() =>
    this.cart().reduce((sum, p) => sum + p.price, 0)
  );

  addToCart(product: Product) {
    this.cart.update(items => [...items, product]);
  }

  constructor(private http: HttpClient) {}
}

Now:
  • API → handled by RxJS
  • UI state → handled by Signals
  • Templates stay clean
  • No subscriptions anywhere
  • High performance
  • Fully reactive
When To Use Which
Use Signals When:

  • Managing component state
  • Building dashboards
  • Forms
  • Derived UI values
  • Performance-sensitive UI
  • Working zoneless
Use BehaviorSubject When:
  • Handling async event streams
  • WebSockets
  • Complex operator chains
  • Interacting with legacy RxJS code
  • Advanced reactive flows
Use Hybrid When:
  • Building real-world applications
  • Fetching data from APIs
  • Managing UI state
  • Scaling modern Angular apps
Final Takeaway
BehaviorSubject = Reactive stream tool
Signals = Reactive UI state tool
They solve different problems.

Modern Angular applications should:
  • Use RxJS for async
  • Use Signals for state
  • Bridge them with toSignal()
That gives you:
  1. Cleaner code
  2. Better performance
  3. Easier maintenance
  4. Future-proof architecture


About HostForLIFE

HostForLIFE 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 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Tag cloud

Sign in