I'm pretty much informed of how Angular's Change Detection works, as well as how we can use OnChanges hook for detecting @Input
properties changes, and also a subscribing to ngModel valueChanges in for example a Directive or a Component etc..
Can anyone exaplain what is happening here:
# Custom Directive:
Let's say we have a custom Directive myNumber which has an @Input() property ngModel:
@Directive({
selector: "[myNumber]"
})
class MyNumberDirective implements OnChanges {
@Input() ngModel: any;
constructor(private model: NgModel) {
this.model.control.valueChanges.subscribe(data => {
console.log('directive model changes detected by model control value change subscription');
});
}
ngOnChanges(changes: SimpleChanges){
if(changes.ngModel){
console.log('directive input ngModel changes detected by OnChanges hook');
}
}
}
- In the above example I set subscription to
@Input
property ngModel and directive's model object changes. Changes should be logged in the console when model value changes.
# Component's template:
<input type="number" myNumber [(ngModel)]="number1" />
<input type="number" myNumber [(ngModel)]="number2" />
<input type="number" myNumber [(ngModel)]="number3" (blur)="calculate()" />
We applied myNumber directive on three input elements and each input element has ngModel: number1, number2, number3.
Last input has on blur event to call calculate() method.
# Component's typescript:
calculate() {
this.number1 = 10; // changing ngModel of first input
console.log('number1 changed in a calculate method');
this.number2 = 20; // changing ngModel of second input
console.log('number2 changed in a calculate method');
this.number3 = 30; // changing ngModel of third input
console.log('number3 changed in a calculate method');
}
- I logged a message after each model change in a calculate() method.
- A Directive is listening to ngModel changes and it will log a two messages for each model value change as well.
# Problem:
Angular will execute calculate()
method, change all three models and then detect changes and trigger cd hooks in a Directive:
// calculate() log messages first:
'number1 changed in a calculate method'
'number2 changed in a calculate method'
'number3 changed in a calculate method'
// then number1 model change messages in a directive:
'directive model changes detected by model control value change subscription'
'directive input ngModel changes detected by OnChanges hook'
// then number2 model change messages in a directive:
'directive model changes detected by model control value change subscription'
'directive input ngModel changes detected by OnChanges hook'
// then number3 model change messages in a directive:
'directive model changes detected by model control value change subscription'
'directive input ngModel changes detected by OnChanges hook'
# Solution I would like to simplify:
In the component we can call changeDetection()
after each model change in the calculate()
method. That will trigger directive's change detection hook automatically.
constructor(private ref: ChangeDetectorRef) {}
calculate() {
this.number1 = 10; // changing ngModel of first input
console.log('number1 changed in a calculate method');
this.ref.detectChanges(); // triggering detect changes manually
this.number2 = 20; // changing ngModel of second input
console.log('number2 changed in a calculate method');
this.ref.detectChanges(); // triggering detect changes manually
this.number3 = 30; // changing ngModel of third input
console.log('number3 changed in a calculate method');
this.ref.detectChanges(); // triggering detect changes manually
}
- This way angular will change model and call change detection hook inside a Directive immediately.
# Question:
How to achieve this immediately and change detections without manually writing ref.detectChanges()
after each model change ?
I hope this example will be useful to all you guys having the same problems