TypeError: this.control is undefined

Hi All,

I am trying to get form validation working based on this.

My issue is, I have a selector called control-messages, but I cannot seem to get it to display in the html.

I get the following error in controlMessages.ts.

TypeError: this.control is undefined

That means I am probably doing some incorrect around @Input() control: FormControl;.

Any suggestions appreciated.

Here is my code:

login.html

<form [formGroup]="loginForm" (ngSubmit)="submit()">
    <ion-item>
      <ion-label stacked>Username</ion-label>
      <ion-input type="text" formControlName="username" id="username"></ion-input>
    </ion-item>
    <br>
    <control-messages [control]="loginForm.controls.username"></control-messages>
    <ion-item>
      <ion-label stacked>Password</ion-label>
      <ion-input type="password" formControlName="password" id="password"></ion-input>
    </ion-item>
    <ion-buttons>
      <button type="submit" [disabled]="!loginForm.valid" block round>Sign In</button>
    </ion-buttons>
  </form>

login.ts

import { Component, Input } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Validators } from '@angular/common';
import { REACTIVE_FORM_DIRECTIVES, FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { ControlMessages } from '../validation/controlMessages';
import { RegisterPage } from '../register/register';
import { EmployeeModel } from '../model/EmployeeModel';
@Component({
    templateUrl: 'build/pages/login/login.html',
    directives: [REACTIVE_FORM_DIRECTIVES, ControlMessages]
})
export class LoginPage {
    private loginForm: FormGroup;
    errorMessage: string;
    @Input() control: FormControl;
    constructor(private nav: NavController, private builder: FormBuilder) {
        this.loginForm = builder.group({
            'username': [
                '', // default value
                [Validators.required, Validators.minLength(5)]
            ],
            'password': [
                '',
                [Validators.required, Validators.minLength(5)]
            ]
        });
    }
    submit() {
        if (this.loginForm.dirty && this.loginForm.valid) {
            alert(`Name: ${this.loginForm.value.username} Password: ${this.loginForm.value.password}`);
        }
    }
  }

controlMessages.ts

import { Component, Input } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { ValidationService } from './validationService';
@Component({
  selector: 'control-messages',
  template: `<div *ngIf="errorMessage !== null">{{errorMessage}}</div>`
})
export class ControlMessages {
  //errorMessage: string;
  @Input() control: FormControl;
  constructor() {
    console.log('ControlMessages.constructor'); 
  }
  get errorMessage(): string {
console.log('ControlMessages.errorMessage');    
    for (let propertyName in this.control.errors) {
      if (this.control.errors.hasOwnProperty(propertyName) && this.control.touched) {
        return ValidationService.getValidatorErrorMessage(propertyName, this.control.errors[propertyName]);
      }
    }
    
    return null;
  }
}

*The console.logs: ControlMessages.errorMessage: undefined

validationService.ts

import { FormControl, FormGroup } from "@angular/forms";
interface ValidationResult {
    [key: string]: boolean;
}
export class ValidationService {
    static getValidatorErrorMessage(validatorName: string, validatorValue?: any) {
        let config = {
            'required': 'Required',
            'invalidCreditCard': 'Is invalid credit card number',
            'invalidEmailAddress': 'Invalid email address',
            'invalidPassword': 'Invalid password. Password must be at least 6 characters long, and contain a number.',
            'minlength': `Minimum length ${validatorValue.requiredLength}`
        };
        return config[validatorName];
    }
    static creditCardValidator(control) {
        // Visa, MasterCard, American Express, Diners Club, Discover, JCB
        if (control.value.match(/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/)) {
            return null;
        } else {
            return { 'invalidCreditCard': true };
        }
    }
}

I’ve updated the above to work now.

Does anyone know how I can use the validator above, and call a non static object from a static validation method?

For example, when I try the following, I get this error:

error

EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in ./LoginPage class LoginPage_Host - inline template:0:0
ORIGINAL EXCEPTION: TypeError: validator is null

login.ts

constructor(private nav: NavController, private builder: FormBuilder) {

this.loginForm = builder.group({
    'username': [ '', [Validators.required, Validators.minLength(5), Validators.maxLength(55), ValidationService.userNameValidator(this.control, this.employeeService)] ],
    'password': [ '', [Validators.required, Validators.minLength(5), Validators.maxLength(45), ValidationService.passwordValidator] ]
});

}

validationService.ts

public static userNameValidator(control: FormControl, employeeService: EmployeeService): ValidationResult {
    console.log('userNameValidator: ' + employeeService+' - '+control);
    if (employeeService) {
         employeeService.getEmployeByUserName(control.value).then((employeeModel: EmployeeModel) => {
             if (employeeModel) {
                 return { userNameExists: true };
             } else {
                 return null;
             }
         });
    }
    return null;
}

console.log: userNameValidator: undefined - undefined