简体   繁体   中英

Why ngModel don't trigger changedetection in writevalue method?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM