我写了一个非常简单的自定义表单控件,我没有更改它的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);
}
}
然后我在名为ngmodel-demo 的组件中使用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) {}
}
当我运行应用程序时,我发现计数器组件的值为1,但其视图未更新。
然后我设置一个计时器来更新ngModel并标记为check。
ngOnInit() {
setInterval(() => {
this.count = ++this.count;
this._cdRef.markForCheck();
}, 3000);
}
结果是每次计数器组件的视图显示的值是最后一个ngModel的值。
在writeValue方法中手动调用markForCheck有效。但我没有使用onPush策略,我不明白为什么要手动调用?
还有一个难题就是为什么在writeValue中调用onChange也可以。
stackblitz上的在线演示链接:https://stackblitz.com/edit/angular-cfc-writevalue