I wrote a very simple custom form control and I didn't change it's changeDetectionStrategy.
@Component({
selector: 'counter',
template: `
<button (click)="increase($event)">+</button>
{{counter}}
<button (click)="decrease($event)">-</button>
`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CounterComponent),
multi: true
}]
})
export class CounterComponent implements OnInit, ControlValueAccessor {
private counter: number = 0;
private onChange: (_: any) => void;
private onTouched: () => void;
constructor(private _cdr: ChangeDetectorRef) { }
ngOnInit() { }
writeValue(value) {
console.log(`Write value`, value);
this.counter = value;
// this._cdr.markForCheck(); // it works
// Use onChange works too
// if (this.onChange) {
// this.onChange(value);
// }
}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
increase() {
this.counter++;
this.onChange(this.counter);
}
decrease() {
this.counter--;
this.onChange(this.counter);
}
}
Then I use it in a component named ngmodel-demo with onPush changeDetectionStrategy.
@Component({
selector: 'ngmodel-demo',
template: `
<h3>NgModel Demo</h3>
<p>Count: {{count}}</p>
<counter [(ngModel)]="count"></counter>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NgmodelDemoComponent {
@Input() name: string;
public count = 1;
constructor(private _cdRef: ChangeDetectorRef) {}
}
When I ran the app, I found that the counter component have got the value 1, but its view didn't update.
Then I set a timer to update the ngModel and mark for check.
ngOnInit() {
setInterval(() => {
this.count = ++this.count;
this._cdRef.markForCheck();
}, 3000);
}
The result is that each time the value that counter component's view shows is the value of the last ngModel's.
Manually calling markForCheck in writeValue method works. But I did not use the onPush strategy, I do not understand why to manually call?
There is also a puzzle that is why calling onChange in writeValue also works.
Online demo link on stackblitz: https://stackblitz.com/edit/angular-cfc-writevalue
It is a bug in Angular. I opened an issue about it. You can subscribe if interested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With