Change detection is the process Angular runs to find template bindings whose values changed and write the new values to the DOM. How it is triggered and how much of the tree it visits depends on whether the app uses zone.js, OnPush, or signals.
Angular templates contain bindings such as {{ qty }} or [items]="items". Angular does not know when the underlying values change, so it periodically re-evaluates the bindings, compares each result with the value it stored last time, and updates the DOM only where the result differs. This comparison is called dirty checking, and a full run of it is a change detection pass.
In a classic application the pass is triggered by zone.js. zone.js monkey-patches browser APIs such as addEventListener, setTimeout, Promise.then and XMLHttpRequest so that every callback runs inside an Angular zone. When the callback finishes and the microtask queue drains, NgZone emits onMicrotaskEmpty and ApplicationRef.tick() walks the whole component tree from the root, checking every binding in every Default-strategy component whether or not anything relevant changed.
ChangeDetectionStrategy.OnPush lets a component opt out of that blanket check. An OnPush view is skipped unless something marks it dirty: an @Input received a new reference (compared with Object.is), a template event fired inside the view, an async pipe emitted, or ChangeDetectorRef.markForCheck() was called. Marking a view also marks its ancestors, so the next tick can reach it without checking the siblings along the way.
Signals make the trigger precise instead of coarse. A template that reads a signal registers itself as a consumer in a reactive graph. Writing the signal marks its consumers dirty, which flags exactly those views for refresh and asks the scheduler for a tick. In a zoneless app (provideZonelessChangeDetection) that notification is the only trigger, so the traversal visits the flagged views and passes through their ancestors without evaluating anything else.
Interview framing: define Angular Change Detection in one sentence, then explain one concrete runtime behavior and one common pitfall with a short code example.