Component and change detection trees in Angular applications
Tags: angular
Published: 2023-01-23 19:14:45

---
title: Component and change detection trees in Angular applications
published: true
description: 
tags: angular
canonical_url: https://indepth.dev/posts/1512/change-detection-and-component-trees-in-angular-applications
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ps2v1fhxy410o0k5rbf.png
---

> This article is an excerpt from my [Angular Deep Dive](https://courses.indepth.dev/angular?utm_source=devto&utm_medium=article&utm_campaign=component-trees) course

# Components tree

With component based approach in web applications, composition is achieved by including child components in templates. For this reason, we can think of an Angular application as a tree of components. However, under the hood, for components Angular uses a low-level abstraction called `View`. It’s a smallest grouping of elements which are created and destroyed together. All operations like property checks and DOM updates are performed on views, **hence it’s more technically correct to state that angular is a tree of views**, while a component can be described as a higher level concept of a view.

## View related data structures

The structure of a `View` is defined by the [LView](https://github.com/angular/angular/blob/da7318e2fa9d35af46387965f92b6871ca7946a4/packages/core/src/render3/interfaces/view.ts#L79) interface. `LView` stores all of the information needed to process the instructions as they are invoked from the template. Each component and an embedded view has its corresponding `LView`. We can refer to views created for components as component views to distinguish from the embedded views created through [ViewContainerRef](https://github.com/angular/angular/blob/a6d5fe202cafb419f3beb8d09711132124b6aa9a/packages/core/src/linker/view_container_ref.ts#L52) using [template references](https://github.com/angular/angular/blob/5509e3512f9542896dbbc267752a5034be6df9f6/packages/core/src/linker/template_ref.ts#L39), i.e.`ng-template` elements.

The hierarchy of views is tracked using designated properties on `LView`:

```ts
export const PARENT = 3;
export const NEXT = 4;
export const CHILD_HEAD = 13;
export const CHILD_TAIL = 14;

export interface LView {
  [CHILD_HEAD]: LView|LContainer|null;
  [CHILD_TAIL]: LView|LContainer|null;
  [PARENT]: LView|LContainer|null;
  [NEXT]: LView|LContainer|null;
}
```

To traverse the tree of views Angular uses these [traversal utils] (https://github.com/angular/angular/blob/a98fa489fb498273bdfde2fa4598893d1d53582e/packages/core/src/render3/util/view_traversal_utils.ts).

Angular also implements [TView](https://github.com/angular/angular/blob/da7318e2fa9d35af46387965f92b6871ca7946a4/packages/core/src/render3/interfaces/view.ts#L519) data structure that holds static data for an `LView`. This `TView` is shared between all `LViews` of a given type. This means that each instance of a particular component has its own instance of `LView`, but they all reference the same instance of `TView`.

The last bit we need to know is that Angular has a few different view types [defined](https://github.com/angular/angular/blob/da7318e2fa9d35af46387965f92b6871ca7946a4/packages/core/src/render3/interfaces/view.ts#L492) like this:

```ts
export const enum TViewType {
  Root = 0,
  Component = 1,
  Embedded = 2,
}
```

`Component` and `Embedded` view types should be self explanatory. The `Root` view is a special type of views that Angular uses to bootstrap top-level components into. It is used in conjunction with `LView` which takes an existing DOM node not owned by Angular and wraps it in `LView` so that other components can be loaded into it.

There is a direct relationship between a view and a component — one view is associated with one component and vice verse. A view holds a [reference](https://github.com/angular/angular/blob/da7318e2fa9d35af46387965f92b6871ca7946a4/packages/core/src/render3/interfaces/view.ts#L172) to the associated component class instance in the [CONTEXT](https://github.com/angular/angular/blob/da7318e2fa9d35af46387965f92b6871ca7946a4/packages/core/src/render3/interfaces/view.ts#L36) property. All operations like property checks and DOM updates are performed on views.

For a template that includes `A` component twice the data structures will look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1c1itycs2o30rxqcih8r.png)

## Change detection tree

In most applications you have one main tree of component views that starts with the component you reference in the `index.html`. There are other root views that are created through [portals](https://material.angular.io/cdk/portal/overview), mostly for modal dialogs, tooltips etc. These are the UI elements that need to be rendered outside of the hierarchy of the main tree mostly for styling purposes, for example, so that they are not effected by `overflow:hidden`.

Angular keeps top level elements of such trees in a `_views` property of the [ApplicationRef](https://github.com/angular/angular/blob/ff84c7360334792a9a422bd0fa0353e0cf670525/packages/core/src/application_ref.ts#L720). Those trees are referred to as change detection trees, because they are traversed when Angular runs change detection globally. The [tick](https://github.com/angular/angular/blob/ff84c7360334792a9a422bd0fa0353e0cf670525/packages/core/src/application_ref.ts#L1001) method that runs change detection iterates over each tree in `_views` and runs the check for each view by calling `detectChanges` method:

```ts
@Injectable({ providedIn: 'root' })
export class ApplicationRef {
  tick(): void {
    try {
      this._runningTick = true;
      for (let view of this._views) {
        view.detectChanges();
      }
      if (typeof ngDevMode === 'undefined' || ngDevMode) {
        for (let view of this._views) {
          view.checkNoChanges();
        }
      }
    } catch (e) { ... } finally { ... }
  }
}
```

You can also see that `tick` runs `checkNoChanges` method on the same set of views.

## Attaching dynamic views to ApplicationRef

Angular allows to render a component into a standalone DOM element outside of Angular’s change detection tree. But since those views also need to be checked, `ApplicationRef` implements methods `attachView()` and `detachView()` to add/remove standalone views to change detection trees. This effectively adds those views to the `_views` array that’s traversed during change detection.

Let’s see this example. We have `M` component that we want to instantiate dynamically and then render into the DOM that’s outside main Angular tree. Here’s how we do it:

```ts
@Component({
  selector: 'l-cmp',
  template: 'L'
})
export class L {
  constructor(moduleRef: NgModuleRef<any>, appRef: ApplicationRef) {
    const resolver = moduleRef.componentFactoryResolver;
    const factory = resolver.resolveComponentFactory(M);

    let newNode = document.createElement('div');
    newNode.id = 'placeholder';
    document.body.prepend(newNode);

    const ref = factory.create(moduleRef.injector, [], newNode);
    appRef.attachView(ref.hostView);
  }
}

@Component({
  selector: 'm-cmp',
  template: '{{title}}'
})
export class M {
  title = 'I am the component that was created dynamically';
}
```

This is what we’ll see if we check the DOM structure in the application:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q0e6x7gs7rib6kmjbz8a.png)

If we now take a look at `_views` property, this is what we’ll see:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8l8ayg4ikqfgnk3hctvs.png)

We can use console to find out what those `RootViewRef` instances represent:

```text
const TVIEW = 1;
const CONTEXT = 8;
const CHILD_HEAD = 13;

const view_1 = appRef._views[0];
const view_2 = appRef._views[1];

view_1._lView[TVIEW].type // 0 - HostView
view_1._lView[CONTEXT].constructor.name // M

view_1._lView[CHILD_HEAD][TVIEW].type // 0 - HostView
view_1._lView[CHILD_HEAD][CONTEXT].constructor.name // M

view_2._lView[CONTEXT].constructor.name // AppComponent (RootView)
view_2._lView[TVIEW].type // 0 - HostView

view_2._lView[CHILD_HEAD][CONTEXT].constructor.name // AppComponent (ComponentView)
view_2._lView[CHILD_HEAD][TVIEW].type // 1 - ComponentView

view_2._lView[CHILD_HEAD][CHILD_HEAD][CONTEXT].constructor.name // L
```

The chart will show these relationships clearer:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/civrn0sz3lq5warrzswo.png)

## Bootstrapping multiple root components

It's possible to bootstrap multiple root components like this:

```ts
@NgModule({
  declarations: [ AppComponent, AppRootAnother ],
  imports: [  BrowserModule ],
  bootstrap: [ AppComponent, AppRootAnother ]
})
export class AppModule {}
```

which will create two root views and corresponding html tags:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gumdbhgv2uqaivy2qhah.png)

The only thing to remember is that `index.html` should include tags for both selectors:

```html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>LearnAngular</title>
</head>
<body>
  <app-root></app-root>
  <app-root-another></app-root-another>
</body>
</html>
```

With this setup Angular will create two independent change detection trees. They will be registered under `ApplicationRef._views` and when `ApplicationRef.tick()` function will be called Angular will run change detection for both trees. This is in effect similar to using [attachView](https://github.com/angular/angular/blob/ff84c7360334792a9a422bd0fa0353e0cf670525/packages/core/src/application_ref.ts#L1032). However, they will still be part of a single `ApplicationRef`, so they will share the injector defined for the `AppModule`.