虚拟方法触发角度变化检测?

时间:2019-11-22 17:13:43

标签: angular angular7 angular-forms angular-changedetection

您好,我尝试了解角度的​​变化检测。

我有一个用于内联文本编辑的父组件my-editable和一个带有样式输入元素的子组件my-input。我正在使用从父组件到子组件的响应式表单。
现在,如果子组件的输出属性status发出新事件,我的父组件将调用其方法dummy(),而无需任何表达式。

我感到困惑的是,父级的更改检测显然触发了!
如果我从(status)="dummy()"中删除了行my-editable.component.html,则模板中的错误消息(<small class="error">{{ formControl.errors.msg }}</small>)将不会显示。
我认为,更改检测应该由(status)="cdr.detectChanges()"或类似的东西触发。

有人可以向我解释吗?

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>

1 个答案:

答案 0 :(得分:0)

昨天刚看过this awesome talk

您应该在14:30到17:00之间找到答案。

TLDR :拥有OnPush时,@Input数据更改以及内部事件发生时,更改检测将触发