3

I saw there is a topic which looks like mine but it doesn't really answer my problem because we don't manage the errors in the same way. FormBuilder group is deprecated

First of all, I just migrated to Angular 11 and I have this problem now:

group is deprecated: This api is not typesafe and can result in issues with Closure Compiler renaming.
Use the `FormBuilder#group` overload with `AbstractControlOptions` instead.

In this page I generate automatically many forms on my page and in the case of a date range I use two datepickers. I created a function for checking the values in the 2 date pickers.

Component:

newGroup = this.fb.group(
        {
          [node.type + '_' + node.objectId + '_dateFrom']: [
            '',
            [Validators.required]
          ],
          [node.type + '_' + node.objectId + '_dateTo']: [
            '',
            [Validators.required]
          ]
        },
        {
          validator: CheckFromToDate(
            node.type + '_' + node.objectId + '_dateFrom',
            node.type + '_' + node.objectId + '_dateTo'
          )
        }
      );

Validator:

export function CheckFromToDate(fromName: string, toName: string) {
  return (formGroup: FormGroup) => {
    const from = formGroup.controls[fromName];
    const to = formGroup.controls[toName];
    const dateFrom = new Date(from.value);
    const dateTo = new Date(to.value);
    const today = new Date();
    if (to.errors && from.errors) {
      // return if another validator has already found an error on the matchingControl
      return;
    }
    if (!from.value) {
      from.setErrors({ wrongDate: true });
      to.setErrors(null);
    } else if (!to.value) {
      to.setErrors({ wrongDate: true });
      from.setErrors(null);
    } else if (dateFrom.getTime() < -3600000) {
      from.setErrors({ wrongDate: true });
      to.setErrors(null);
    } else if (dateFrom > today) {
      from.setErrors({ wrongDate: true });
      to.setErrors(null);
    } else if (dateTo.getTime() < -3600000) {
      to.setErrors({ wrongDate: true });
      from.setErrors(null);
    } else if (dateTo > today) {
      to.setErrors({ wrongDate: true });
      from.setErrors(null);
    } else if (dateFrom.getTime() > dateTo.getTime()) {
      from.setErrors({ fromTo: true });
      to.setErrors({ fromTo: true });
    } else {
      from.setErrors(null);
      to.setErrors(null);
    }
  };
}

How can I make my validators work with the new way of handling validators in Angular 11?

halfer
  • 19,824
  • 17
  • 99
  • 186
user3659739
  • 434
  • 6
  • 19

2 Answers2

11

Change your validator signature from

return (formGroup: FormGroup) 

to

return (controls: AbstractControl) 

Then change the way you access the controls from

const from = formGroup.controls[fromName];

to

const from= controls.get(fromName);

Also change the way you report the errors back from

from.setErrors({ wrongDate: true });

to

return from.setErrors({ wrongDate: true }); // note the return statement.

One final change would be to change

newGroup = this.fb.group(
        {
           ...
        },
        {
          validator: CheckFromToDate(
            node.type + '_' + node.objectId + '_dateFrom',
            node.type + '_' + node.objectId + '_dateTo'
          )
        }
      );

to

newGroup = this.fb.group(
        {
           ...
        },
        {
          validator: CheckFromToDate(
            node.type + '_' + node.objectId + '_dateFrom',
            node.type + '_' + node.objectId + '_dateTo'
          )
        } as AbstractControlOptions
      );

Note the casting to AbstractControlOptions and that should remove the deprecated warning.

You can refer the official documentation for a detailed explanation.

James Poulose
  • 3,569
  • 2
  • 34
  • 39
0

User, a Validators should return or an object (if error) or null (if not error). You souldn't use setError. replace yours from.setErrors and to.setErrors, you can return,e.g. if there're an error an object like

{errorFrom:...,errorTo:...}

So, your validator like

return (formGroup: FormGroup) => {
    ...
    const error={errorFrom:null,errorTo:null}

    if (to.errors && from.errors) {
      // return if another validator has already found an error on the matchingControl
      return null;
    }
    if (!from.value) {
      error.errorFrom="wrong Date from"
    } else if (!to.value) {
      error.errorTo="wrong Date to"
    } else if (dateFrom.getTime() < -3600000) {
      error.errorFrom="wrong Date from"
    } else if (dateFrom > today) {
      error.errorTo="From greater than today"
    } else if (dateTo.getTime() < -3600000) {
      error.errorTo="wrong Date to"
    } else if (dateTo > today) {
      error.errorTo="To greater than today"
    } else if (dateFrom.getTime() > dateTo.getTime()) {
      error.errorTo="from greater than to"
      error.errorFrom="from greater than to"
    }
    //if error.errorTo!=null or error.errorFrom!=null, the error, else null
    return error.errorTo || error.errorFrom? error:null;
  };

and you control as usually

 <span *ngIf="form.get(node.type + '_' + node.objectId + '_dateFrom').errors?.errorFrom>
  {{form.get(node.type + '_' + node.objectId + '_dateFrom').errors.errorFrom}}
 </span>
Eliseo
  • 50,109
  • 4
  • 29
  • 67