Gili Yaniv
Gili Yaniv

Reputation: 3211

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.

Upvotes: 2

Views: 808

Answers (1)

Radim Köhler
Radim Köhler

Reputation: 123861

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"];
    }
}

Upvotes: 2

Related Questions