Reputation: 4522
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.
Upvotes: 2
Views: 16653
Reputation: 11241
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>
Upvotes: 1
Reputation: 2488
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.
Upvotes: 3