首页 > 解决方案 > 带有回调的 Angular @Output

问题描述

是否可以与 进行回调@Output

我有一个FormComponent检查有效性,并在提交时禁用提交按钮。现在我想在提交完成后重新启用提交按钮。

@Component({
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      ...
    </form>
  `
})
class FormComponent {
  form: FormGroup = ...;

  isSubmitting = false;

  @Output()
  submitted = new EventEmitter<MyData>()

  onSubmit() {
    if(this.form.invalid || this.isSubmitting) {
      return;
    }

    this.isSubmitting = true;

    this.submitted.emit(this.form.value);
    // Here I'd like to listen for the result of the parent component
    // something like this...
    // this.submitted.emit(...).subscribe(res => this.isSubmitting = false);
  }
}
@Component({
  template: `
    <my-form (submitted)="onSubmitted($event)"></my-form>
  `
})
class ParentComponent {
  constructor(private service: MyService) { }

  onSubmitted(event: MyData) {
    this.service.doSomething(event).pipe(
      tap(res => console.log("service res", res)
    );
    // basically I'd like to `return` this `Observable`,
    // so the `FormComponent` can listen for the completion
  }
}

我知道,我可以使用@Input()insideFormComponent并执行以下操作:

@Input()
set submitted(val: boolean) {
  this.isSubmitted = val;
}

但我想知道是否有更简单/更好的解决方案,因为isSubmitted应该是 的内部属性FormComponent,它应该由组件本身而不是其父级管理。

标签: angularcallbackrxjseventemitter

解决方案


 onSubmit() {
    this.isSubmitting = true;
    this.submitHandler(this.form.value).subscribe(res => {
      this.isSubmitting = false;
      this.cdr.markForCheck();
    });
  }

在上面的示例代码中,该函数onSubmit()不是无状态函数,而是依赖于外部处理程序。从测试的角度来看,使函数本身不可预测。如果失败(如果失败),您将不知道在哪里、为什么或如何。在组件被销毁,回调也会被执行。

禁用的问题是组件使用者的外部状态。所以我只是把它变成一个输入绑定(就像这里的其他答案一样)。这使组件更干燥,更容易测试。

@Component({
  template: `<form [formGroup]="form" (ngSubmit)="form.valid && enabled && onSubmit()"</form>`
})
class FormComponent {
  form: FormGroup = ...;

  @Input()
  enabled = true;

  @Output()
  submitted = new EventEmitter<MyData>()

  onSubmit() {
    // I prefer to do my blocking in the template
    this.submitted.emit(this.form.value);
  }
}

这里的主要区别是我enabled$ | async在下面使用来支持OnPush更改检测。由于组件的状态是异步更改的。

@Component({
  template: `<my-form [enabled]="enabled$ | async" (submitted)="onSubmitted($event)"></my-form>`
})
class ParentComponent {
  public enabled$: BehaviorSubject<boolean> = new BehaviorSubject(true);

  constructor(private service: MyService) { }

  onSubmitted(event: MyData) {
    this.enabled$.next(false);
    this.service.doSomething(event).pipe(
      tap(res => this.enabled$.next(true)
    ).subscribe(res => console.log(res));
  }
}

推荐阅读