Debugging Like a Boss in Angular 9

Anthony Humes

Debugging

This is going to rock!

What happens next?

What can we learn?

to be able to debug any application, you have to understand the tools you can use

ng.probe

New API in Angular 9

Comes directly from Ivy internal methods

Where can I access the new methods?

// Global variable in the console
ng

{
  getComponent: ƒ getComponent(element),
  getContext: ƒ getContext(element),
  getListeners: ƒ getListeners(element),
  getOwningComponent: ƒ getOwningComponent(elementOrDir),
  getHostElement: ƒ getHostElement(componentOrDirective),
  getInjector: ƒ getInjector(elementOrDir),
  getRootComponents: ƒ getRootComponents(elementOrDir),
  getDirectives: ƒ getDirectives(element),
  applyChanges: ƒ applyChanges(component)
}

Before we start...what is $0?

$0

<p class="some-element"></p>
<div class="some-div">
  <p class="some-element">
    Hey there text!
  </p>
</div>

most recent selection from the Elements Inspector or from using Inspect Element

Get Angular Elements

ng.getComponent

ng.getDirectives

ng.getListeners

ng.getComponent

ng.getDirectives

ng.getListeners

retrieves the component from an HTML element

retrieves an array of directives from an HTML element

returns an array of both html (ex. click) and host listeners for an HTML element

ng.getComponent

<app-parent class="some-div">
  <app-child class="some-element">
    Hey there text!
  </app-child>
</app-parent>
ng.getComponent($0)

ChildComponent {...}

ng.getDirectives

<app-element class="some-div">
  <p appExample appOther class="some-element">
    Hey there text!
  </p>
</app-parent>
ng.getDirectives($0)

[ExampleDirective {...}, OtherDirective {...}]

ng.getListeners

export class ExampleComponent {
  
  @HostListener('mouseover', ['$event'])
  onHover($event: MouseEvent) {
    // some action on hover
  }
}
ng.getListeners($0)

[{
  element: app-example,
  name: "mouseover",
  callback: f wrapListenerIn_markDirtyAndPreventDefault(e),
  useCapture: false,
  type: "dom"
}]
<app-element class="some-div">
  <p (click)="itemClicked($event)" class="some-element">
    Hey there text!
  </p>
</app-parent>

ng.getListeners

<app-element class="some-div">
  <p (click)="itemClicked($event)" class="some-element">
    Hey there text!
  </p>
</app-parent>
ng.getListeners($0)

[{
  element: p.some-element,
  name: "click",
  callback: f wrapListenerIn_markDirtyAndPreventDefault(e),
  useCapture: false,
  type: "dom"
}]

Why ng.getComponent?

  • Debug specific components in isolation
  • Debug *ngFor by looking at specific items

Why ng.getDirectives?

  • Discover all directives attached to a
    specific element
  • Make changes to specific instances
    of directives

Why ng.getListeners?

  • Discover all listeners attached to
    an element
  • Run listeners without triggering
    the corresponding event

ng.applyChanges

let component = ng.getComponent($0)

component.value = 10;

ng.applyChanges($0)
<app-element class="some-div">
  <p class="some-element">
    5
  </p>
</app-parent>
<app-element class="some-div">
  <p class="some-element">
    10
  </p>
</app-parent>

triggers change detection for the component or directive

Why ng.applyChanges?

  • Debugging Change Detection Issues
  • Testing the effect of changes made to
    components/directives

ng.getOwningComponent

ng.getContext

ng.getOwningComponent

<app-element class="some-div">
  <p class="some-element">
    Hey there text!
  </p>
</app-parent>
ng.getOwningComponent($0)

ExampleComponent {...}

ng.getContext

<ul>
  <li><app-item></app-item></li>
  <li><app-item></app-item></li>
  <li><app-item></app-item></li>
  <li><app-item></app-item></li>
  <li><app-item></app-item></li>
</ul>
ng.getContext($0)

NgForOfContext {
  first: false
  last: false
  even: true
  odd: false
  $implicit: {name: "Item 3", value: {…}}
  ngForOf: (5) [{…}, {…}, {…}, {…}, {…}]
  index: 2
  count: 5
}

Why ng.getOwningComponent?

  • Use in concert with applyChanges to
    run change detection for wrapping
    component
  • Get the component for any element
    in the DOM

Why ng.getContext?

  • Debug instances of *ngFor and *ngIf
    structural directives
  • Get the context for elements inside
    of *ngFor

ng.getOwningComponent

returns the parent component for the HTML element

ng.getContext

returns the context of an *ngIf or *ngFor for the HTML element

Other Methods

ng.getRootComponents

ng.getInjector

ng.getRootComponents

Retrieves all root components associated with a DOM element, directive or component instance.

Root components are those which have been bootstrapped by Angular.

ng.getInjector

Retrieves an `Injector` associated with an element, component or directive instance.

Note from the Angular Team

The current API is a work in process.  These methods are the starting point to a way more powerful set of debug tools than ng.probe.  More methods and better functionality will be coming in the future.

Demo

Next Steps

  • Experiment with the new methods
  • Spend some time pair programming with another developer
  • Help someone in the community with a problem they can't solve
  • Always keep learning!