2

I am using ReactiveForms in Angular v7.

Template

<div class="login__container">
    <div class="login__form">
        <form novalidate [formGroup]="loginForm" (ngSubmit)="onSubmit()">
            <div class="field">
                <p class="control">
                    <input class="input" type="text" placeholder="Username" formControlName="username" [ngClass]="{ 'is-invalid': submitted && f.username.errors }">
                </p>
            </div>
            <div class="field">
                <p class="control">
                    <input class="input" type="password" placeholder="Password" formControlName="password" [ngClass]="{ 'is-invalid': submitted && f.password.errors }">
                </p>
            </div>
            <div class="field">
                <p class="control">
                    <button class="button is-success" [disabled]="!loginForm.valid">
                        Login
                    </button>
                </p>
            </div>
        </form>
    </div>
</div>

Component

import { Component, OnInit } from '@angular/core'
import { FormBuilder, FormGroup, Validators } from '@angular/forms'

@Component({
    selector: 'app-login-component',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
    loginForm: FormGroup
    submitted = false

    constructor(private fB: FormBuilder) {}

    ngOnInit() {
        this.loginForm = this.fB.group({
            username: ['', Validators.required],
            password: ['', Validators.required]
        })
    }

    // convenience getter for easy access to form fields
    get f() {
        return this.loginForm.controls
    }

    onSubmit() {
        this.submitted = true

        // stop here if form is invalid
        if (this.loginForm.invalid) {
            return
        }

        console.log(this.loginForm.value)
    }
}

When I go to this route, I have a console error

ERROR TypeError: Cannot read property 'controls' of undefined
    at Object.get [as f] (http://localhost:4200/main.js:257:35)
    at http://localhost:4200/vendor.js:92667:9
    at Array.forEach (<anonymous>)
    at deepFreeze (http://localhost:4200/vendor.js:92664:33)
    at http://localhost:4200/vendor.js:92670:7
    at Array.forEach (<anonymous>)
    at deepFreeze (http://localhost:4200/vendor.js:92664:33)
    at http://localhost:4200/vendor.js:92670:7
    at Array.forEach (<anonymous>)
    at deepFreeze (http://localhost:4200/vendor.js:92664:33)

I cannot work out why this happening, the validation around the submit button appears to be working, so I can only assume the fields are being referenced correctly. I suspect the issue is coming from the convenience getter set within the component, however I cannot see what is wrong with this as autocomplete is providing me with the values I expect.

7
  • check first 'this.loginForm' is undefined or not in f method. or else you can use loginForm.controls.username.errors in the HTML. Commented Nov 17, 2018 at 10:26
  • Another option is to pass the formBuilder from ngOnInit cycle to constructor cycle Commented Nov 17, 2018 at 11:02
  • As it is, Im not able to reproduce your issue stackblitz.com/edit/angular-lpstaz Commented Nov 17, 2018 at 14:08
  • As @OmerShukar mentioned, you could try by instantiating the form in the constructor Commented Nov 17, 2018 at 14:09
  • 1
    I fixed it. I moved to React. Commented Aug 4, 2022 at 5:32

2 Answers 2

3

Instead of the convenience method you are using, you could simply reference the field like

[ngClass]="{ 'is-invalid': submitted && loginForm.controls['username'].errors }"

It would then be a case of showing an error message if you so wish using

<div *ngIf="submitted && loginForm.controls['username'].hasError('required')" class="error-message">Username is required</div>

I am not clear on what benefit your current approach is affording you over something straight forward such as this.

Sign up to request clarification or add additional context in comments.

1 Comment

This wont make a difference
1

Should be pretty easy to fix by checking loginForm in html.

<div class="login__container" *ngIf="loginForm"> <!-- Check here -->
    <div class="login__form">
        <form novalidate [formGroup]="loginForm" (ngSubmit)="onSubmit()">
            <div class="field">
                <p class="control">
                    <input class="input" type="text" placeholder="Username" formControlName="username" [ngClass]="{ 'is-invalid': submitted && f.username.errors }">
                </p>
            </div>
            <div class="field">
                <p class="control">
                    <input class="input" type="password" placeholder="Password" formControlName="password" [ngClass]="{ 'is-invalid': submitted && f.password.errors }">
                </p>
            </div>
            <div class="field">
                <p class="control">
                    <button class="button is-success" [disabled]="!loginForm.valid">
                        Login
                    </button>
                </p>
            </div>
        </form>
    </div>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.