49

are reactive forms the way to go in order to have a component that can listen for changes in the validity status of the form it contains and execute some compoment's methods?

It is easy to disable the submit button in the template using templateRef like [disabled]="#myForm.invalid", but this does not involve the component's logic.

Looking at template forms' doc I did not find a way

Cec
  • 1,726
  • 3
  • 18
  • 31

4 Answers4

91

If you want to get only the status and not the value you can use statusChanges:

export class Component {

    @ViewChild('myForm') myForm;

    this.myForm.statusChanges.subscribe(
        result => console.log(result)
    );
}

If you even want data changes, you can subscribe to the valueChanges of the form and check the status of the form using this.myForm.status:

export class Component {

    @ViewChild('myForm') myForm;

    this.myForm.valueChanges.subscribe(
        result => console.log(this.myForm.status)
    );
}

Possible values of status are: VALID, INVALID, PENDING, or DISABLED.

Here is the reference for the same

Caio Ladislau
  • 1,257
  • 13
  • 25
Sravan
  • 18,467
  • 3
  • 30
  • 54
  • Don't know who did the downvote... Since myForm would be an instance of AbstractControl, it is even better to subscribe to form.statusChanges which returns an observable of VALID, INVALID, PENDING or DISABLED. I'm actually a bit worried about PENDING as I don't know its meaning... – Cec Apr 05 '18 at 07:34
  • Pending is when the Angular is in middle of a validation check, when it starts validating and going through all the checks, the status starts `pending` and it eventually change to either `Valid` or `Invalid` – Sravan Apr 05 '18 at 07:38
  • and If you dont need the data changes, you can use `statusChanges` – Sravan Apr 05 '18 at 07:41
  • So I can just ignore PENDING and wait for a new stats value to be emitted. Thank you very much :) – Cec Apr 05 '18 at 07:59
  • Thank you @Sravan for the valuable answer. It worked. But is there any way we can delay the change detection like for 5 seconds? Actually I am calling api for saving data and change detection is sending too many requests. Please put some light on it. – Adnan Sheikh Dec 04 '18 at 10:29
  • 2
    @AdnanSheikh you can use `debounceTime` to delay the change detection. Example: `this.myForm.valueChanges.pipe(debounceTime(5000)).subscribe(result => console.log('Form changes', result));`. – HelloWorld101 Aug 21 '20 at 10:38
10

You can do something like this do detect a validity change and execute a method based on whether the form is VALID or INVALID.

this.myForm.statusChanges
  .subscribe(val => this.onFormValidation(val));

onFormValidation(validity: string) {
  switch (validity) {
    case "VALID":
      // do 'form valid' action
      break;
    case "INVALID":
      // do 'form invalid' action
      break;
  }
}
Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
  • 1
    This could be minimised to a ternary operator: `validity === "VALID" ? methodOne() : methodTwo()` *however* I warn to please be careful and not use this approach in large files - it can be weird syntax to consider in large files. – KeaganFouche Jul 04 '19 at 12:42
1

You can subscribe to the whole form changes and implement your logic there.

@ViewChild('myForm') myForm;

this.myForm.valueChanges.subscribe(data => console.log('Form changes', data));
Roberto Zvjerković
  • 9,657
  • 4
  • 26
  • 47
1

I could be late to the party but @Viewchild('anything') may lead to this error

Cannot read properties of undefined (reading 'statusChanges')
Cannot read properties of undefined (reading 'valueChanges')

You can simply subscribe to the form. Code Example:

form:FormGroup;

ngOnInit(){
this.form.valueChanges.subscribe((result: any) =>
      console.log('values changes here') );}
Muhammad Umar
  • 1,291
  • 7
  • 13