3
votes

I have loginForm in my project Stackblitz

But I get an error at 'formControlName':

ERROR TypeError: Cannot read property 'get' of undefined at Object.eval [as updateDirectives] (LoginComponent.html:7) at Object.debugUpdateDirectives [as updateDirectives] (core.js:23910) at checkAndUpdateView (core.js:23306) at callViewAction (core.js:23547) at execComponentViewsAction (core.js:23489) at checkAndUpdateView (core.js:23312) at callViewAction (core.js:23547) at execEmbeddedViewsAction (core.js:23510) at checkAndUpdateView (core.js:23307) at callViewAction (core.js:23547)

My login component:

  initForm() {
    this.loginForm = this.fb.group({
    email: ['', Validators.required ],
    password: ['', Validators.required]     
   });
    }

I don't understand where the error appears.

my input-field component Stackblitz

 value:string;
 onChange: ()=> void;
 onTouched: ()=> void;
 disabled:boolean;
  ngOnInit() {
   }
  writeValue(value: string): void {
  this.value = value ? value: '';  
   }
  registerOnChange(fn: any): void {
   this.onChange =fn;
   }
   registerOnTouched(fn: any): void {
   this.onTouched=fn;
   }
   setDisabledState?(isDisabled: boolean): void {
   this.disabled = isDisabled;
   } 

What Am I missing?

2

2 Answers

4
votes

You could write a small function to return controls in a cleaner way so in you html you could have the example given below. The error is related to how you are trying to access your controls.

<div class="alert alert-danger" *ngIf="email.dirty">

And then return the control so you have proper get access. Looking like so.

import { AbstractControl } from '@angular/forms'; //correct type to return.


public get email(): AbstractControl
{
    return this.loginForm.controls.email
}

This will then allow you to access you controls for the respective form group. You could write one for each control you would like to access.You could also return the form and then just access the control you would like. This above stops the errors in you stackblitz and shows the result in the JSON on screen. Comment if you have any trouble.

A nice benefit of this is that in your controller as well as template you can use it to perform quick checks.

if (this.email.valid)
{
    // any logic where you require a specific form control to be valid.
}

Documentation for Angular Forms.

3
votes

referring to your code at stackblitz

This is your form

this.loginForm = this.fb.group({
      email: ['', Validators.required ],
      password: ['', Validators.required]     
    });

and in HTML you have missed the form name

<div class="form-group">
        <app-input-field formControlName="email"></app-input-field>
        <div class="alert alert-danger" *ngIf="loginForm.get('email').dirty && personalProfileForm.get('email').hasError('required')">
          email Required
        </div>
        <app-input-field formControlName="password"></app-input-field>
        <div class="alert alert-danger" *ngIf="loginForm.get('password').dirty && personalProfileForm.get('password').hasError('required')">
          password Required
        </div>
      </div>

Just replace personalProfileForm with loginForm in your html

Additionally, advice by @dince12 is perfect in order to make your html code looks more easy to read, cheers!

If you want more details on that example, you can refer below article : http://jasonwatmore.com/post/2018/05/10/angular-6-reactive-forms-validation-example and below is an small example:

create public property like this

public get myform() { return this.myform.controls; }

and use it like this

<input type="text" formControlName="firstName" class="form-control" [ngClass]="{ 'is-invalid': submitted && myform.firstName.errors }" />
                            <div *ngIf="submitted && myform.firstName.errors" class="invalid-feedback">
                                <div *ngIf="myform.firstName.errors.required">First Name is required</div>
</div>