ngOnChanges does not fire in directive component


#1

A directive I wrote does not seem to respond to changes in its @Input() varible - the directive’s ngOnChanges() does not fire when its @Input() variable changes value in another component. Here’s the setup, simplified:

Directive code:

@Component({
    selector: 'my-directive',
    template: '<...>'
})
export class MyDirective {
    @Input private value: number;
    ...
    ngOnChanges(changeRecord) {
        for (var change in changeRecord) {
            if (change === 'value') {
                <change stuff on page to reflect change in this.value>
            }
        }
    }
}

Code of component that uses the directive:

@Page({
    template: '<... <directive [value]="valueToCommunicate"> ...'
    directives: [MyDirective]
})
export class MyPage {
    ...
    someFunction() {
        ...
        this.valueToCommunicate = newValue;
        ...
    }
}

In MyDirective, ngOnChanges() does not fire every time this.valueToCommunicate changes inside MyPage. The directive’s ngOnChanges() function gets called only when either the page is resized or when another button on the page is clicked but it does not fire when no user events occur in MyPage.

More specifically: MyPage changes this.valueToCommunicate as per the code above, at regular intervals, inside a loop that uses setTimeout(). Those changes do not get communicated to the directive, unless a UI user event has happened in MyPage.

I have a fix, for now, but it seems like a total hack and I’m concerned it would impact performance: the fix is to start another setTimeout() loop, inside the MyDirective and repeatedly calls, at some rate, this.ref.markForCheck(), where this.ref is a ChangeDetectorRef object imported from angular2/core.

If anybody has seen and solved this issue, could you please mention how to properly perform change detection in the directive that’s based on programmatic (non UI) changes to the communicated variable?

NOTE: this issue is similar to issue 42824 but (a) I’m not sure it’s the same issue, (b) there is no answer there. If this appears to solve the other issue, I’ll merge the two issues somehow.

NOTE: There’s a lot of relevant info here on change detection here still sifting through it…

Thanks!


Detect change to @input variable programmatically - equivalent to watch
#3

The code snippet above is actually correct and change detection via ngOnChanges would work fine for the code displayed.

The reason it wasn’t working is that some code was missing from it. Specifically, the call to this.valueToCommunicate = newValue was happening inside a promise:

navigator.mediaDevices.getUserMedia(..).then(.. this.valueToCommunicate = new Value ..)

which was called from MyPage

as soon as I put that assignment statement outside of the promise, change detection worked.

Semi-conclusion: change detection on a variable does not happen automatically when a variable is changed inside a promise. I’m not sure why, or if it’s specific to promises in general vs. the browser’s built-in mediaDevices code.


#4

Any news on this issue?

I was working on a previous project using Ionic 2 beta 4, and I didn’t have this issue. I’m wondering if it’s a new bug, as you say, with promises.