2

I have a reactive form as following:

this.form = this.formBuilder.group({
  name: ['', Validators.required],
  email: ['', this.customValidator()]
});

I also have a "submit" button with a [disabled] condition:

<button [disabled]="form.invalid" (click)="create()">Create</button>

If email input is untouched and I modify name input, customValidator is not fired and Create button enables despite the customValidator() would return an error.

On the other hand, the name control has a Validators.required validation that is fired even if the input is untouched, which is the desired behaviour.

Example on stackblitz: I want the email input to be required (and the create button to be disabled) when name has value on it even if email is untouched.

Iñigo
  • 1,877
  • 7
  • 25
  • 55

4 Answers4

1

Found a couple ways for solving the problem:

1 Angular cross-validation.

The custom validator is applied to the FormGroup and not to the FormControl. The validation is executed every time the form is modified.

this.form = this.formBuilder.group({
  name: ['', Validators.required],
  email: ['']
}, { validators: this.customValidator});

2 Subscribe to form valueChanges + updateValueAndValidity.

this.form = this.formBuilder.group({
  name: ['', Validators.required],
  email: ['', this.customValidator()]
});

And on ngOnInit, whenever the form changes, the validation is executed:

this.form.valueChanges.subscribe(x => {
    this.form.get('email').updateValueAndValidity();
})
Iñigo
  • 1,877
  • 7
  • 25
  • 55
  • That is indeed the case, cross-validation solves the behavior problem, but that should not mark email input in red if you just click on it and then focus out. From user's perspective that only work if email is never required. It does not make much sense to disable button if email input is empty but not mark it as invalid, how are u supposed to understand that button is disabled because you have not introduced email? – tony May 25 '22 at 11:35
1

Please check this solution. Instead of abstratcontrol I've used FormControl which is much easier to handle. Also you can pass the parent-child param to the custom validator as seen on this example:

 ngOnInit() {
    this.form = this.formBuilder.group({
      name: ['', Validators.required],
      email: ['', this.customVal('name')], -> you can pass the value here
    });
  }

Please check the stackblitz for complete solution.

https://stackblitz.com/edit/angular-custom-validator-uhhicz?file=src/app/app.component.ts

Bozhinovski
  • 2,496
  • 3
  • 20
  • 38
  • Still enabling Create button when only filling `name` input – Iñigo May 26 '22 at 07:11
  • @Iñigo its fixed now. Please check it out – Bozhinovski May 30 '22 at 07:24
  • what was the solution? its still not working as you can see here: https://stackblitz.com/edit/angular-custom-validator-mwz3sg?file=src%2Fapp%2Fapp.component.ts%3AL35,src%2Fapp%2Fapp.component.html if you try to save the form its valid even if the fields are not the same (I've changed the validator) – Elazar Zadiki Aug 25 '22 at 13:44
0

Can you try this :

  ngOnInit() {
    this.form = this.formBuilder.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, this.customVal()]],
    });
  }
Deunz
  • 1,776
  • 19
  • 32
  • 1
    I don't want it to be required always, the custom validator logic is just an example to demonstrate that the validation is only fired when touched. – Iñigo May 25 '22 at 10:01
0

As Iñigo say, a FormControl only is "validate" if is modify the input or if you call manually to "updateValueAndValidity".

So another way is subscribe to form.get('name').valueChange (not forget unsubscribe)

this.form.get('name').valueChange.subscribe(_=>{
  this.form.get('email').updateValueAndValidity()
})

Or we can use input event in .html

<input formControlName="name" class="form-control" placeholder="Name" 
      (input)="form.get('email').updateValueAndValidity()" />
Eliseo
  • 50,109
  • 4
  • 29
  • 67