ngOnChanges not firing when input property changed

ngonchanges not working with array
ngonchanges not working for objects
ngdocheck
ngonchanges not updating view
ngonchanges not working angular 9
ngonchanges not detecting changes in object
trigger ngonchanges manually
ngdocheck vs ngonchanges

Can you programatically trigger angular's change detection when mutating a component property in angular2?

@Component({
   selector: 'my-component', 
})
class MyComponent implements OnChanges {
   @Input() message: string;

   ngOnChanges(changeRecord) {
      for (var change in changeRecord) {
         console.log('changed: ' + change);
      }
   }

   doSomething() {
     // I want ngOnChanges to be called some time after I set the 
     // message. Currently it is only called if the host element
     // changes the value of [message] on the element.
     this.message = 'some important stuff';
   }
}

I was having the same issue, and this is a simple but not very elegant workaround I am using. Pass in another property to force trigger ngOnChanges method

<div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger"></div>

In the parent component class, whenever you want to manually fire the ngOnChanges method on child component, just modify "changeTrigger" property

ParentComponent Class (poll-stat-chart is the child component)

     @Component({
        directives: [PollStatChartCmp],
        template: `
            <div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger">
            </div>
            <button (click)="triggerChild()"></button>
        `
      }
    export class ParentComponent {
        changeTrigger = 1;
        barData = [{key:1, value:'1'}, {key:2, value'2'}];
        triggerChild() {
            this.barData[0].value = 'changedValue';

            //This will force fire ngOnChanges method of PollStatChartComponent
            this.changeTrigger ++ ;           
        }

    }

And then in child component class, add a property [changeTrigger]

    @Component({
        selector: '[poll-stat-chart]',
        inputs: ['barData', 'changeTrigger'],
        template: `
            <h4>This should be a BAR CHAR</h4>
        `
    })
    export class PollStatChartCmp {
        barData;
        changeTrigger;
        constructor(private elementRef: ElementRef) {
            this.render();

        }

        ngOnChanges(changes) {
            console.log('ngOnChanges fired');
            this.render();
        }

        render() { console.log('render fired');}

}

In Angular 4 the hook ngOnChanges is not firing on input, ngOnChanges is not called every time a component property changes internally. It gets called when the databinding from the parent� ngOnChanges is a lifecycle callback of Angulars change detection mechanism and it is called when an @Input() is changed by Angulars data binding. When you have @Input() isLoaded: boolean; and <home-page [isLoaded]="someValue"> and someValue in the parent component is changed, then change detection updates isLoaded and calls ngOnChanges().

Trying to manually call change detection or spent a lot of time on a workaround for this is way overkilling, why not creating a function to handle the desired mutation and call it in both ngOnChanges and doSomething? something like:

@Component({
  selector: 'my-component',
})
class MyComponent implements OnChanges {
  @Input() message: string;
  viewMessage: string;

  ngOnChanges(changes: { [propertyName: string]: SimpleChange }) {
    for (let propName in changes) {
      if (propName === 'message') {
        this.updateView(this.message);
      }
    }
  }

  doSomething() {
    this.viewMessage = 'some important stuff';
  }

  updateView(message: string) {
    this.viewMessage = message;
  }
}

So viewMessage will be the attribute you'll be using and controlling the template.

ngOnChanges only runs when the Input change comes from a , ngOnChanges only runs when the Input change comes from a template binding like <component [someInput]="aValue"> . If you set it manually like this component. someInput = aValue , that happens outside the change detection cycle and you need to let Angular know somehow that you've changed something. The ngOnChnages is a life cycle hook, which angular fires when it detects changes to data bound input property. This method receives a SimpeChanges object, which contains the current and previous property values. There are several ways parent component can communicate with the child component. One of the ways is to use the @Input decorator.

The reason it doesn’t work can be found in the source code.

https://github.com/angular/angular/blob/885f1af509eb7d9ee049349a2fe5565282fbfefb/packages/core/src/view/provider.ts

Where ngOnChanges is called from, and where the SimpleChanges structure is built are very much tied into the component / directive code.

It’s not just a ‘change tracker’ running that looks over every property however it was set, so ngOnChanges only works for bindings set by parent components.

This is where ngDoCheck comes in and possibly KeyValueDiffers.

See also:

https://netbasal.com/angular-the-ngstyle-directive-under-the-hood-2ed720fb9b61 https://juristr.com/blog/2016/04/angular2-change-detection/

[2.2.1] ngOnChanges() doesn't get called when an @Input() property , What is the motivation / use case for changing the behavior? I'm just learning angular2 and ngOnChanges() doesn't seem reliable if it's not called� The method ngOnChanges() uses SimpleChanges as an argument that gives new and previous value of input values after changes. In case of input user object data type, ngOnChanges() is called only when the reference of object is changed in parent component. If we change only values of properties of an input user object then ngOnChanges() method

There seems to be no way to modify an input binding on this and have it detected during change detection. However it was possible to fix the unit test I was writing by wrapping the whole component in another component

@ng.Component({
    selector: 'my-host-component',
    template: '<my-component [message]="message" (change)="change.emit($event)"></my-component>'
    directives: [MyComponent]
})
class MyHostComponent {
   message: string;
   change = new EventEmitter<any>();
}

I then ran the test on MyHostComponent, rather than MyComponent.

I've submitted an issue to angular requesting that a method be added to ComponentFixture so that tests like this are easier to write.

ngOnChanges not being called on child of dynamically created , The gist of it is that ngOnChanges is called when a component's input bindings are changed through the template (as opposed to when the input property is� ngOnChanges. As the Angular core docs clearly states, the ngOnChanges() method is a lifecycle hook that will trigger each time Angular sets a data-bound input property. That means that it should be used whenever we need something to happen whenever that property value changes. This can happen for a number of different reasons, such as: user

ngOnChanges not firing if an #Input is receiving an object, ngOnChanges not firing if an #Input is receiving an object - angular. Angular change detection is triggered when the #Input property value changes. ngOnChanges() link mode_edit code A callback method that is invoked immediately after the default change detector has checked data-bound properties if at least one has changed, and before the view and content children are checked.

When ngOnChanges is not enough – Another dev blog, How to use "ngDoCheck" when "ngOnChanges" is not powerful enough. component inputs and execute some operations in case these inputs change. of this array stay unchanged, so “ngOnChanges” does not get fired. Instead of any, use ngOnChanges(changes: {[propName: string]: SimpleChange}) { console.log(changes.a.currentValue, changes.b.currentValue); }. There's also a previousValue property for each changed input property. – Mark Rajcok Mar 17 '16 at 17:46

Angular2 change detection: ngOnChanges not firing for nested object, In Angular 4 the hook ngOnChanges is not firing on input, ngOnChanges is not called every time a component property changes internally. It gets called when� ngOnChanges triggers following the modification of @Input bound class members. Data bound by the @Input() decorator come from an external source. When the external source alters that data in a detectable manner, it passes through the @Input property again. With this update, ngOnChanges immediately fires. It also fires upon initialization of

Comments
  • To manually run change detection, try using ApplicationRef.tick(). However, I don't believe ngOnChanges() will be called, since the host property didn't change. Why are you changing a child property in the child component that is an input property?
  • The code above isn't the actual code, I was just using it to demonstrate the issue. My real code is a unit test and I've obtained an instance of the component using TestComponentBuilder. I want the unit test code to modify the value of the message property and to check that an event is emitted from the code in ngOnChanges. But after a couple of hours head scratching I can't figure out any way to accomplish that. I've also tried modifying the nativeElement on the DebugElement to no effect.
  • I was looking for a method like ComponentFixture.modifyHostBinding(property: string, newValue: any), or something similar, but there doesn't seem to be anything like it, so I posed a more generic question.
  • Did you get the answer?
  • what you want to do here is create a dummy host component like TestHostComponent that will bind message property as per norm. Then check for the change to the message property using fixture.detectChanges() in your test. see related: stackoverflow.com/questions/37408801/…
  • Such an elegant hack.