1

I am trying to set the whole fromGroup to invalid with a custom validator, which doesn't seems to work...

The goal of the code bellow is to compare two instance of a fromGroup.

  • If they matched it means no changes has been made so it has to be invalid.
  • Else it doesn't match it means changes has been made so it has to be valid.

My variable isValid works correctly when I logged it. It turns to true or false depending on changes.

But I cannot manage to make the from invalid, I've tried many ways form articles and stack-overflow, which has a stackblitz whichi doesn't seems to work neither.

Like this.updateCyclistForm.setErrors({ 'invalid': true}); from Angular 6 Required only one field from many fields Reactive Form

I've seen many similar posts has this one which use controls which is not the case here.

public updateCyclistForm: FormGroup
public savedStateOfForm: FormGroup

...

constructor(...) {
    ...
    this.savedStateOfForm = new FormGroup({
        status: new FormControl(this.currentReg.status, []),
        role: new FormControl(this.currentReg.role, []),
        passes: new FormControl({ data: this.passesUID }, [])
    })
    this.updateCyclistForm = new FormGroup({
        status: new FormControl(this.currentReg.status, []),
        role: new FormControl(this.currentReg.role, []),
        passes: new FormControl({ data: this.passesUID }, [])
    })
    this.updateCyclistForm.setValidators(this.isValid(this.savedStateOfForm));
}
    
...

isValid = (clone: FormGroup): ValidatorFn => {
    return (group: FormGroup): ValidationErrors => {
        let isValid = JSON.stringify(clone.value) != JSON.stringify(control.value)
        group.setErrors({ 'valid': isValid });
        this.updateCyclistForm.setErrors({ 'valid': isValid });
        return
    }
}

HTML

<button type="submit" [disabled]="!updateCyclistForm.valid">Save</button>

The button is never disabled, why ? What am I doing the wrong way ?

EDIT :

I've also tried to use something similar as @Adam's answer. Which make my button disabled for life.

  isValid = (clone: FormGroup): ValidatorFn => {
        return (group: FormGroup) : ValidationErrors => {
            return {
                invalid: JSON.stringify(clone.value) != JSON.stringify(group.value) ? true : null
              }
        }
    }
crg
  • 4,284
  • 2
  • 29
  • 57
  • 1
    ok, so your button is disabled, you are very very close. You **MUST** return null from your validator if your control is valid. You cannot return anything else, it is all in the documentation. – Adam Jenkins May 25 '21 at 11:54
  • I thought I was returning `null` but it was a null object. Thanks for your help – crg May 25 '21 at 12:11

2 Answers2

1

setValidators must accept a ValidatorFn function that returns ValidationErrors (or null)

constructor() {

   // ...

   this.updateCyclistForm.setValidators(this.updateCyclistValidator);
}


...

updateCyclistValidator(ctrl: FormGroup) {
   const valid = // run your validation uisng the values in ctrl

   // if there are no errors, you MUST return null
   if(valid) return null;

   // return your errors, for example:
   return {
     role: 'choose a role'
   }
    
}

The presence or absence of errors returned from your validator tells angular if your form is valid or not.

Adam Jenkins
  • 51,445
  • 11
  • 72
  • 100
  • I've also tried something similar, which did not work. So it make me think that the problem is probably in my `button`. In your answer how would you use `[disabled]` property ? – crg May 25 '21 at 10:52
  • @crg - I'd use disabled exactly as you have used it. Did you use something similar? Or did you use exactly what I posted? Do not use `this` inside the `updateCyclistValidator`. Post what you have tried that is similar. – Adam Jenkins May 25 '21 at 11:00
  • I used something similar as your code. Your code does not match what I expect to do. But I tried to get inspired of it. In my function `isValid` I changed the return value for `return { invalid: JSON.stringify(clone.value) != JSON.stringify(group.value) ? true : null }`. – crg May 25 '21 at 11:24
  • 1
    @crg - You aren't using `setErrors` correctly either. `setErrors({valid:true})` still results in an invalid form. Why your button isn't disabling I don't know. Post your entire component (and template). Maybe this simple example will help you out: https://stackblitz.com/edit/angular-ivy-d4tqq6?file=src%2Fapp%2Fapp.module.ts – Adam Jenkins May 25 '21 at 11:52
0

Thanks to the help of @Adam

This is the solution which came out

isValid = (clone: FormGroup) => {
    return (group: FormGroup) => {
        return JSON.stringify(clone.value) != JSON.stringify(group.value) ? null : { invalid: JSON.stringify(clone.value) != JSON.stringify(group.value) }
    }
}
crg
  • 4,284
  • 2
  • 29
  • 57