Gili Yaniv Gili Yaniv - 2 months ago 20
TypeScript Question

Angular 2 + typescript Can't find property on compile time

I'm trying to build a custom form validation method in angular 2.
The problem is that when I run the project I'm getting the following error:

Property 'controls' does not exist on type 'AbstractControl'.


But if I ignore it and continue using my app I see that the validate function works as planed.

Anyone else face this issue ? Why I'm getting this errors?
I'm gassing that is somehow related to typescript rather then to the angular itself (I'm using typescript 2.0.3).

This is my code:

imports:

import {Injectable} from '@angular/core';
import {RegexService} from "./regex.service";
import {FormControl, ValidatorFn} from "@angular/forms";


The custom validate function:

requireGroupMinAmount(minPossibleAmount): ValidatorFn {
return (control: FormControl): string[]=> {
let requireCounter = 0;
if (!control)
return null;


controlsLoop:for (let formOptionKey in control.controls) {
for (let formOptionValue in control.controls[formOptionKey].controls) {
if (control.controls[formOptionKey].controls[formOptionValue].value)
requireCounter++;
if (requireCounter >= minPossibleAmount)
break controlsLoop;
}
}

return requireCounter >= minPossibleAmount
? null
: ["Please fill at least " + minPossibleAmount + " fields"];
}
}


Thanks in advance.

Answer

The child collection/dictionary controls is defined on derived classes FormGroup and FormArray. So, if we want to iterate FormGroup (which controls are of type dictionary), we would need to do this check:

if (control instanceof FormGroup)
{
    controlsLoop:for (let formOptionKey in control.controls) {
    ...
    }
}

no compiler (and even runtime) will properly iterate only if that abstract control is FormGroup instance

Also, we have to be sure, that coming value is AbstractControl

requireGroupMinAmount(minPossibleAmount): ValidatorFn {
    //return (control: FormControl): string[]=> {
    return (control: AbstractControl): string[]=> {

and not the subtype FormControl. Only abstract base could be properly check if is it of some of its subtypes (e.g. FormArray)

There is adjusted code snippet (check in playground):

requireGroupMinAmount(minPossibleAmount): validatorFn{
    return (control: AbstractControl): string[] => {
        let requireCounter = 0;
        if (!control)
            return null;

        if (control instanceof FormGroup) {
            controlsLoop: for (let formOptionKey in control.controls) {

                var childControl: AbstractControl = control.controls[formOptionKey];

                if (childControl instanceof FormGroup) {
                    for (let formOptionValue in childControl.controls) {
                        if (childControl.controls[formOptionValue].value)
                            requireCounter++;
                        if (requireCounter >= minPossibleAmount)
                            break controlsLoop;
                    }
                }
            }
        }

        return requireCounter >= minPossibleAmount
            ? null
            : ["Please fill at least " + minPossibleAmount + " fields"];
    }
}
Comments