首页 文章

为什么ngModel不会在writevalue方法中触发changedetection?

提问于
浏览
2

我写了一个非常简单的自定义表单控件和 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);
  }
}

然后我在名为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) {}
}

当我运行应用程序时,我发现计数器组件的值为1,但 its view didn't update .

然后我设置一个计时器来更新ngModel并标记检查 .

ngOnInit() {
  setInterval(() => {
    this.count = ++this.count;
    this._cdRef.markForCheck();
  }, 3000);
}

结果是每次计数器组件的视图显示的值是最后一个ngModel的值 .

在writeValue方法中手动调用markForCheck有效 . 但我没有使用onPush策略,我不明白为什么要手动调用?

还有一个难题是为什么在writeValue中调用onChange也有效 .

stackblitz上的在线演示链接:https://stackblitz.com/edit/angular-cfc-writevalue

1 回答

  • 1

    这是Angular中的一个错误 . 我开了一个关于它的issue . 如果感兴趣,您可以订阅 .

相关问题