12

I am using FormGroup, custom validators, etc. I need to capture in an event handler when the form becomes valid/invalid, not a property, but an actual event in TypeScript code.

I took a look to the documentation, but I wasn't able to find something like: (validityChange)="myEventHandler($event)"

where validityChange is just a placeholder for the name of the actual event I am looking for.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Will de la Vega
  • 536
  • 1
  • 5
  • 17
  • If there is no event or @Output() for valid state change in a form, what would be the best way to implement this (I mean, 'the angular way') ? – Will de la Vega Sep 14 '16 at 23:02

3 Answers3

16

Subscribe to statusChanges

this.myForm.statusChanges
.filter(s => s == 'VALID')
.subscribe(val => onValid())
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
8

For Angular with RxJs 6+ (where you need to use pipe):

this.form.statusChanges
  .pipe(
    filter(() => this.form.valid))
  .subscribe(() => this.onFormValid());

this.form.valid is a property that is boolean and so will either be true or false. Hence the filter will return true when the form is valid and the subscribe will then only call this.onFormValid() when the property is true.

You can see what is going on by doing this:

  public ngOnInit() {
    this.form.statusChanges
      .pipe(
        filter((status: string) => {console.log(status); return this.form.valid}))
      .subscribe(() => this.onFormValid());
  }

  private onFormValid() {
    console.log('form is valid')
  }

One should also unsubscribe or take (complete), eg:

this.form.statusChanges
  .pipe(
    filter(() => this.form.valid)),
    takeUntil(this.destroy$)
  .subscribe(() => this.onFormValid());

ngOnDestroy() {
  this.destroy$.next();
}
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • Isn't the observable self-destructed? Do we have to handle ngOnDestroy? – Narayan Dheeraj Kumar Aug 26 '21 at 07:26
  • 1
    When you're not sure (as I was not at the time) then it's safer to unsubscribe. More info: https://stackoverflow.com/questions/52841211/is-it-necessary-to-unsubscribe-angular-form-statuschanges-valuechanges-observabl They say it's an EventEmitter under the hood, so probably we don't need to unsubscribe in this case. – rmcsharry Aug 26 '21 at 14:44
3

Borrowing the idea from @Gunter's answer, but utilizing the current API you can simplify it and drop the usage of the 'VALID' constant from your code by using the valid property:

this.myForm.statusChanges
    .filter(() => this.myForm.valid)
    .subscribe(status: string => onValid());

By the way, depending on whether this subscription could lead to a memory leak, do not forget to unsubscribe() from it.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
  • Seems to be something wrong with your code? status:string is delcared in your filter but you are not comparing it to anything, so your filter will not actually do anything. Your anonymous function inside the .filter() is simply returning .valid which is a boolean. Your explanation seems to imply (status: string => status == this.myForm.valid) ? – rmcsharry Feb 22 '19 at 18:57
  • @rmcsharry: `filter()` expects a function returning a `boolean` depending on whether a current item should or shouldn't pass the filter. `this.myForm.valid` returns a `boolean` depending on whether the form is valid, thus establishing the filter. The confusing part is that `status` value isn't needed for the filter, that's why it's not used. Probably, the syntax could be simplified to take the `status` away, but I'm not sure. – Alexander Abakumov Feb 22 '19 at 22:01
  • Yes I was confused by the status: string declaration. It can be removed and then just use an anonymous function: filter(() => this.form.valid)) – rmcsharry Feb 23 '19 at 13:13
  • @rmcsharry I've reverted your edit, because it's incorrect. – Alexander Abakumov Sep 25 '19 at 22:47
  • Good catch on the extra bracket, sorry about that typo! – rmcsharry Sep 26 '19 at 16:37