Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular OnPush Component, does DOM event force Angular to call markForCheck() automatically?

I'm reading about Zone.JS and the Angular change detection process, in the code source, Zone.JS notifies Angular about changes and run the verification in the first component from top to bottom by propagating the check into all components, but in my tests, I had peculiar behavior.

Check my sample:

http://plnkr.co/edit/QPHBQ7cYg9JFZr2oVnGZ?p=preview

The sample has the following architecture:

<app-component>
    <child-component>
        <grand-child-component>

They are nested within each other, none of them have @Input properties, and all of them are OnPush, and they display a simple value in the view like:

view:

{{getComponentValue}}

typescript

value = "app component";

get getComponentValue() { // <-- ES6 get to log when Angular check
    console.log('change detection checking here in component app-component')
    return this.value;
}

you can check this code in the sample.

When the application is started we can see the log:

check component app
check component child
check component grand child

Cool, but, now let's create a scenario if grand-child triggers an DOM event?

Changing the view in the grand child

<button (click)="undefined"> {{getComponentValue}} </button>  
<!-- (click)="undefined" trigger an event -->

And then we have the log:

check component app
check component child
check component grand child

I was expecting when I clicked on the grand-child button, the event would start in the app-component, But as all of them are OnPush, the event was not going to catch the grand-child component because no @Input properties weren't changed, and I would have to manually call the markforcheck or detectchanges, but the code above looks like I invoked the markforcheck.

I called settimeout, interval and events with observables within in grand-child component and none of them invoked changes (check the grand-component ts), only view events (click) the check is called...

The verification is happening, you can test e.g: in the child or in the app component you can add setInterval that increments a value And you can check the view, realize that only when the grand-child triggers the (click) values of your ancestors are updated!

Therefore are they forced by simulating a markForCheck() when a DOM event is triggered, actually is it happening?

like image 765
Gustavo Costa Avatar asked Dec 08 '25 13:12

Gustavo Costa


1 Answers

Yes, that's by design: a bound event triggers markForCheck internally

export function dispatchEvent(
    view: ViewData, nodeIndex: number, eventName: string, event: any): boolean {
  const nodeDef = view.def.nodes[nodeIndex];
  const startView =
      nodeDef.flags & NodeFlags.ComponentView ? asElementData(view, nodeIndex).componentView : view;
  markParentViewsForCheck(startView); // <== this line
  return Services.handleEvent(view, nodeIndex, eventName, event);
}

See also

  • Change Detection issue -- Why is this changing when it's the same object reference with On Push
like image 83
yurzui Avatar answered Dec 11 '25 01:12

yurzui



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!