How to debug Angular apps

Debugging Angular applications efficiently requires understanding the available tools and techniques to identify and fix issues quickly. With over 12 years of Angular development experience since 2014 and as the creator of CoreUI, I’ve debugged countless production issues in enterprise applications. Angular provides powerful debugging capabilities through browser DevTools, Angular DevTools extension, and built-in error messages. This approach helps you quickly identify component state issues, change detection problems, and service errors.

Use browser DevTools and Angular DevTools extension to debug Angular applications with breakpoints, component inspection, and performance profiling.

Install Angular DevTools:

Chrome/Edge: Install “Angular DevTools” extension from browser store.

Browser console debugging:

// app.component.ts
import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  template: `
    <div>
      <h1>{{ title }}</h1>
      <button (click)="handleClick()">Click me</button>
      <ul>
        <li *ngFor="let item of items">{{ item }}</li>
      </ul>
    </div>
  `
})
export class AppComponent {
  title = 'My App'
  items = ['Item 1', 'Item 2', 'Item 3']

  handleClick() {
    // Add console.log for debugging
    console.log('Button clicked')
    console.log('Current items:', this.items)

    // Use debugger statement to pause execution
    debugger

    this.items.push(`Item ${this.items.length + 1}`)

    // Log component state
    console.table(this.items)
  }
}

Debug component lifecycle:

import { Component, OnInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'

@Component({
  selector: 'app-user',
  template: '<div>{{ user?.name }}</div>'
})
export class UserComponent implements OnInit, OnChanges, OnDestroy {
  @Input() userId: number

  user: any

  ngOnChanges(changes: SimpleChanges) {
    console.log('ngOnChanges:', changes)
    console.log('Previous userId:', changes['userId']?.previousValue)
    console.log('Current userId:', changes['userId']?.currentValue)
  }

  ngOnInit() {
    console.log('ngOnInit - Component initialized')
    console.log('userId:', this.userId)
    this.loadUser()
  }

  ngOnDestroy() {
    console.log('ngOnDestroy - Component destroyed')
  }

  private loadUser() {
    console.log('Loading user...')
    // Debug API calls
    this.userService.getUser(this.userId).subscribe({
      next: (data) => {
        console.log('User loaded:', data)
        this.user = data
      },
      error: (err) => {
        console.error('Error loading user:', err)
      }
    })
  }
}

Debug services:

import { Injectable } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { tap, catchError } from 'rxjs/operators'
import { throwError } from 'rxjs'

@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private http: HttpClient) {
    console.log('UserService initialized')
  }

  getUsers() {
    console.log('Fetching users...')
    return this.http.get('/api/users').pipe(
      tap(data => console.log('Users received:', data)),
      catchError(error => {
        console.error('Error fetching users:', error)
        return throwError(() => error)
      })
    )
  }

  createUser(user: any) {
    console.log('Creating user:', user)
    return this.http.post('/api/users', user).pipe(
      tap(response => console.log('User created:', response))
    )
  }
}

Using Angular DevTools:

  1. Open browser DevTools (F12)
  2. Navigate to “Angular” tab
  3. Inspect component tree
  4. View component properties
  5. Modify values in real-time
  6. Profile change detection
  7. View dependency injection tree

Debug change detection:

import { Component, ChangeDetectorRef, ApplicationRef } from '@angular/core'

@Component({
  selector: 'app-debug',
  template: '<div>{{ counter }}</div>'
})
export class DebugComponent {
  counter = 0

  constructor(
    private cdr: ChangeDetectorRef,
    private appRef: ApplicationRef
  ) {
    // Monitor change detection
    this.appRef.isStable.subscribe(stable => {
      console.log('App stable:', stable)
    })
  }

  increment() {
    console.log('Before:', this.counter)
    this.counter++
    console.log('After:', this.counter)

    // Force change detection
    this.cdr.detectChanges()
    console.log('Change detection triggered')
  }
}

Debug routing:

import { Router, NavigationStart, NavigationEnd, NavigationError } from '@angular/router'

constructor(private router: Router) {
  this.router.events.subscribe(event => {
    if (event instanceof NavigationStart) {
      console.log('Navigation started:', event.url)
    }
    if (event instanceof NavigationEnd) {
      console.log('Navigation ended:', event.url)
    }
    if (event instanceof NavigationError) {
      console.error('Navigation error:', event.error)
    }
  })
}

Debug templates:

<!-- Use json pipe to inspect objects -->
<pre>{{ user | json }}</pre>

<!-- Check if variables are defined -->
<div>User exists: {{ !!user }}</div>
<div>User ID: {{ user?.id || 'No ID' }}</div>

<!-- Debug expressions -->
<div>{{ debugExpression() }}</div>

Enable production mode debugging:

// main.ts
import { enableProdMode } from '@angular/core'

// Comment out to enable debugging in production build
// enableProdMode()

Best Practice Note

Use console.log strategically—remove before committing. The debugger statement pauses execution in DevTools for step-by-step debugging. Angular DevTools shows component hierarchy, state, and change detection runs. Use RxJS tap operator to debug Observable streams without affecting data flow. Source maps in development mode map compiled code back to TypeScript. This is how we debug CoreUI Angular applications—combining browser DevTools, Angular DevTools, strategic logging, and breakpoints to quickly identify and resolve component, service, and performance issues in production-grade applications.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
How to concatenate a strings in JavaScript?
How to concatenate a strings in JavaScript?

How to Detect a Click Outside of a React Component
How to Detect a Click Outside of a React Component

What is Double Question Mark in JavaScript?
What is Double Question Mark in JavaScript?

How to check if an array is empty in JavaScript?
How to check if an array is empty in JavaScript?

Answers by CoreUI Core Team