简体   繁体   English

Angular 由虚拟方法触发的变化检测?

[英]Angular change detection triggered by dummy method?

Hello, I try to understand the change detection of angular.你好,我试着了解一下angular的变化检测。

I have a parent component my-editable for inline text edit and a child component my-input with a styled input element.我有一个用于内联文本编辑的父组件my-editable和一个带有样式输入元素的子组件my-input I'm working with reactive forms which is piped from parent to child component.我正在使用从父组件到子组件的反应式 forms。
Now if the output property status from child component emit a new event, my parent component call its method dummy() without any expression.现在,如果来自子组件的 output 属性status发出一个新事件,我的父组件将调用它的方法dummy()而没有任何表达式。

What me confused is that the change detection in parent obviously triggered!我感到困惑的是,父母的变化检测显然被触发了!
If I remove the line (status)="dummy()" from my-editable.component.html the error message ( <small class="error">{{ formControl.errors.msg }}</small> ) in template wouldn't be shown.如果我从my-editable.component.html中删除行(status)="dummy()" ,则模板中的错误消息( <small class="error">{{ formControl.errors.msg }}</small> )不会显示。
In my opinion, the change detection should be triggered by (status)="cdr.detectChanges()" or something similar.在我看来,更改检测应该由(status)="cdr.detectChanges()"或类似的东西触发。

Can anyone explain it to me?谁能给我解释一下?

my-input.component.ts
@Component({
  selector: 'my-input',
  ...
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyInput implements OnInit, OnDestroy {

  ...

  @Input('control')
  set control(control: AbstractControl) {
    this.formControl = control as FormControl;
    this.formGroup = control.parent;
  }

  @Output('status') statusOutput = new EventEmitter<string>();
  set status(status: string) {
    if (status) {
      this.statusOutput.emit(status);
      this.statusClass = status.toLowerCase();
      this.cdr.detectChanges();
    } else {
      this.statusClass = false;
    }
  }

  public statusClass: false | string;

  public formGroup: FormGroup | FormArray;
  public formControl: FormControl;

  ...

  constructor(
    ...
    private cdr: ChangeDetectorRef
  ) {...}

  public ngOnInit(): void {
    this.status = this.formControl.status;
    this.updateOnStatusChange();
    ...
  }

  ...

  private updateOnStatusChange(): void {
    this.formControl.statusChanges
      .pipe(pairwise(), untilDestroyed(this))
      .subscribe(([lastStatus, status]) => {
        if (status !== lastStatus) {
          this.status = status;
        }
      });
  }
}
my-input.component.html
<i [ngClass]="statusClass" *ngIf="statusClass"></i>
<input [formControl]="formControl" [placeholder]="placeholder">
my-editable.component.ts
@Component({
  selector: 'my-editable',
  ...
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyEditableComponent {

  ...

  @Input('control')
  set control(control: AbstractControl) {
    this.formControl = control as FormControl;
  }

  ...

  public formControl: FormControl;

  ...

  public dummy() {} // <<< MAGIC

  ...

}
my-editable.component.html
...

<ng-container [ngSwitch]="currentMode">

  <ng-template [ngSwitchCase]="EditModes.READONLY">
    <p>{{ formControl.value }}</p>
  </ng-template>

  <ng-template [ngSwitchCase]="EditModes.EDITABLE">
    <div class="wrapper">
      <p>{{ formControl.value }}</p>
      <button (click)="mode = EditModes.EDIT">
        <i class="edit"></i>
      </button>
    </div>
  </ng-template>

  <ng-template [ngSwitchCase]="EditModes.EDIT">
    <my-input
      (status)="dummy()" <!-- MAGIC -->
      [control]="formControl"
      ...
    ></my-input>
  </ng-template>

</ng-container>

<ng-container [ngSwitch]="formControl.invalid && formControl.touched">

  <ng-template [ngSwitchCase]="true">
    <small class="error">{{ formControl.errors.msg }}</small>
  </ng-template>

  <ng-template [ngSwitchCase]="false">
    <small class="description">{{ description }}</small>
  </ng-template>

</ng-container>

Just watched this awesome talk yesterday.昨天刚看了这个精彩的演讲

You should find your answer somewhere between 14:30 and 17:00.你应该在 14:30 到 17:00 之间找到答案。

TLDR : when you have OnPush , change detection will trigger when @Input data changes , but also when internal events occur . TLDR :当您有OnPush时,更改检测将在@Input数据更改时触发,而且在内部事件发生时也会触发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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