Angular 5 reactive forms validators error - javascript

I have been stuck at this silly angular 5 reactive forms error which i am not able to get rid of. While adding the validation message block in html, I am getting the error
"Cannot read property 'invalid' of undefined"
which is weird as there is a form control element with the same name and I am able to access the value of that feild. Below is the code
HTML file
<form [formGroup]='signUpForm'>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName='password'>
<div *ngIf="password.invalid && (password.dirty || password.touched)"
class="alert alert-danger">
<div *ngIf="password.errors.required">
Name is required.
</div>
</div>
</div>
</div>
</div>
</form>
ts code
signUpForm: FormGroup;
this.signUpForm = new FormGroup({
username:new FormControl('',Validators.required),
email:new FormControl('',[Validators.required]),
password:new FormControl('',Validators.required),
})
Please help. Thanks in advance

Try This Code.
<div *ngIf="signUpForm.controls['password'].invalid && (signUpForm.controls['password'].dirty || signUpForm.controls['password'].touched)"
class="alert alert-danger">
<div *ngIf="signUpForm.get('password').hasError('required')">
Name is required.
</div>
</div>

Where do you initialize the form?? If you do it in ngOnInit(), you should not be facing that problem.
If you are initializing the form under any other custom method of yours then you can use something like:
Use the safe navigation operator ?. This checks whether the first operator results to true or not. When the view is rendered it might be possible that the control is not initialized yet. So suppose if the component variable password is not defined when your view is rendered and you try to access a property invalid of password(which is undefined), you will get the error you get now..
for example:
<div *ngIf="password?.invalid && (password?.dirty || password?.touched)" class="alert alert-danger">
So your actual view could be like:
<form [formGroup]='signUpForm'>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName='password'>
<div *ngIf="password?.invalid && (password?.dirty || password?.touched)" class="alert alert-danger">
<div *ngIf="password?.errors?.required">
Name is required.
</div>
</div>
</div>
</div>
</div>

Related

Angular 7 template driven forms dynamic validation

I am wondering how can I dynamically validate a form input that loops through an array using angular 7. For example if I had a first name and last name field it would have a min characters and a required validator, in the same array I could have an age input that would have a min-max and required validators, I was thinking maybe I should put them into a switch case and send the type to a validate function but I'm not too sure how I could do that
This is the code I have to loop through the array I store the type and name of the input
/*Function to get the form*/
getForm() {
this.api.getForm(this.Param).subscribe(
data => {
this.form = data;
console.log(this.form);
}
);
}
<div class="contents">
<form name="form" (ngSubmit)="onSubmit()" #f="ngForm" novalidate>
<div class="row">
<div *ngFor="let questions of form?.results[0].fields">
<div class="md-form">
<div class="col-12 p-3 ml-2">
<span class="">{{questions.name}}</span><br />
<input mdbInput type="{{questions.type}}" />
</div>
</div>
</div>
</div>
</form>
</div>
I was also looking at reactive forms but I don't think it would work for what I need. Thank you in advance

jQuery validate single input in similar forms

I have two forms on a page that are identical, but I'm trying to validate the one field (which is email in this case), but I can't seem to get it to just validate the one input field as it just shows the error for both forms.
HTML:
<div class="general-form">
<div class="email-error" style="display:none;">
<p>You need valid email</p>
</div>
<div class="form-wrap">
<div class="form-row">
<input id="from-email" type="email" name="email" placeholder="Your Email" />
</div>
<div class="btn-row">
<button class="submit-btn">Submit</button>
</div>
</div>
</div>
<div class="general-form">
<div class="email-error" style="display:none;">
<p>You need valid email</p>
</div>
<div class="form-wrap">
<div class="form-row">
<input id="from-email" type="email" name="email" placeholder="Your Email" />
</div>
<div class="btn-row">
<button class="submit-btn">Submit</button>
</div>
</div>
</div>
JS:
$(".submit-btn").on("click", function() {
var $this = $(this);
var valid_email = $this.find("#from-email").val();
if (/(.+)#(.+){2,}\.(.+){2,}/.test(valid_email)) {
return true;
} else {
$this.parents().find(".email-error").show();
return false;
}
});
Overall, I can get it to pass through the validation, but the error message shows for both forms and I'm not sure how to get it so it only shows the error message for that particular form. I'm guessing that I'm pushing too far up the chain and it's testing for both of the forms, but I can't remember which one to target specifically if that makes any sense.
You doubled the id from-email that’s why. In your JS you are checking all fields with the id from-email in this case both of the inputs are checked because both the id.
If one of them is wrong you are searching for the email-error in all of your parents which will go up to the body and then find all off the error wrappers. $this.parents(“.general-form“) will do the deal and only go up to the wrapper of the input and error in your case.
Always make sure your id’s are unique.
Just add required> attribute and add this js
$("#formid").validate();

Unable to assign form control to template variable in Reactive Forms - angular?

I am new to angular let say, i have reactive form like follow
ngOnInit() {
this.registerFormGroup = this.formBuilder.group({
email: [ '', Validators.compose([Validators.required, Validators.email])],
password: this.formBuilder.group({
first: [ '', Validators.required ],
second: [ '', Validators.required, ]
})
});
}
and my angular template looks like follow
<div class="container">
<form [formGroup]="registerFormGroup"
(ngFormSubmit)="registerUser(registerFormGroup.value)" novalidate>
<div class="form-group" >
<label for="email">Email</label>
<input type="email" formControlName="email" placeholder="Enter Email"
class="form-control">
</div>
<div *ngIf="!registerFormGroup.get('password').get('first').valid"
class="alert alert-danger">
</div>
<div class="form-group text-center">
<button type="submit" class="btn btn-success btn-lg"
[disabled]="!registerFormGroup.valid">Submit</button>
</div>
For example, email field has two validations such as required and email type validate so depends upon the error I have to display error message so in my template am using like
<div *ngIf="!registerFormGroup.get('email').valid && (registerFormGroup.get('email').touched)"
class="alert alert-danger">
</div>
Instead of adding same registerFormGroup.get('email') again and again i trying to create template expression like #emailForm="registerFormGroup.get('email')" in
<input type="email" formControlName="email" placeholder="Enter Email" class="form-control" #emailForm="registerFormGroup.get('email')">
so that i can use use like
<div *ngIf="!emailForm.valid" class="alert alert-danger">
</div>
but i am getting error like
compiler.es5.js:1690 Uncaught Error: Template parse errors:
There is no directive with "exportAs" set to "registerFormGroup.get('email')" ("l>
]#emailForm="registerFormGroup.get('email')">
what mistake i made??
You can create common function to access form like below:
validateFormControl(controName: string) {
let control = registerFormGroup.get(controName);
return control.invalid && control.touched;
}
In Templete use this call wherever you need, you just need to pass your control name in function, you can modify this function as per your need as well and you do not need to use form.get all the time. This makes your template more cleaner and performance efficient.
<div *ngIf="validateFormControl('email')"
class="alert alert-danger">
error message
</div>
<div *ngIf="validateFormControl('password')"
class="alert alert-danger">
error message
</div>
Create a method on the component that returns if the form is valid or not and return it in the component
checkError(){ // either you can pass the form from the template or use the component for decleration
return registerFormGroup.get('email').valid;
}
In the template call
<div *ngIf="checkError()" class="alert alert-danger">
// Always make sure not to use controls in the template it will result in AOT compilation error
</div>
try this :
component.html
<div class="container">
<form [formGroup]="registerFormGroup"
(ngFormSubmit)="registerUser(registerFormGroup.value)" novalidate>
<div class="form-group" [ngClass]="{'has-error':!registerFormGroup.controls['email'].valid}">
<label for="email">Email</label>
<input type="email" formControlName="email" placeholder="Enter Email"
class="form-control">
<p class="alert alert-danger" *ngIf="registerFormGroup.controls['email'].dirty && !registerFormGroup.controls['email'].valid">Invalid email address</p>
</div>
<div class="form-group text-center">
<button type="submit" class="btn btn-primary" [disabled]="!registerFormGroup.valid">Submit</button>
</div>
</form>
</div>
component.ts
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
export class AppComponent implements OnInit {
registerFormGroup: any;
constructor(
private formBuilder: FormBuilder
) {}
ngOnInit() {
this.registerFormGroup = this.formBuilder.group({
email: [null , Validators.compose([Validators.required, Validators.email])]
});
}
}
Angular team strongly discourage from using functions outputs in templates due to change detection strategy. You might be interested in following solution, using ngForm directive:
<div class="container">
<form [formGroup]="registerFormGroup"
(ngFormSubmit)="registerUser(registerFormGroup.value)" novalidate>
<div class="form-group" >
<label for="email">Email</label>
<input type="email" formControlName="email" placeholder="Enter Email "
class="form-control" #email="ngForm">
</div>
<div *ngIf="email.invalid"
class="alert alert-danger">
</div>
It's still a hush to copy-paste it in template, but at least you might have direct reference to control via it's template variable. I personally go with controller getter function still, but I'm posting this answer for sake of answer completeness.
Although I agree with the accepted answer (you should have a dedicated method in your form component that will encapsulate the validation process)
sometimes you need a quick check in the template:
The trick is to expose the formGroup from your component and use it like so:
Template:
<input id="name" class="form-control"
formControlName="name" required
[class.is-invalid]="
f.name.invalid &&
(f.name.touched ||
f.name.touched.dirty)">
Component:
//easily access your form fields
get f() { return this.checkoutForm.controls; }
I was also looking for a more elegant solution than calling form.get multiple times. Here is what I come up with using ngif
<div class="col-sm-6" *ngIf="form.get('sponsor') as sponsor">
<input type="text" formControlName="sponsor" id="sponsor" class="form-control" name="sponsor"
[class.is-invalid]="sponsor.errors && sponsor.touched">
</div>
using the as feature on ngIf to create a template variable

How do i debounce form in angular2

I went through lots of post, but did not find what I was looking for.
Basically,
I am showing user validation on form changes. My template looks like this:
<div class="form-group"
[class.error]="!loginForm.find('email').valid && loginForm.find('email').touched">
<div class="input-wrapper">
<input type ="email"
class="form-control"
id="email-input"
placeholder="Email"
formControlName="email">
</div>
<div *ngIf="loginForm.controls['email'].dirty && !loginForm.controls['email'].valid"
class="alert-msg">Email is invalid</div>
</div>
And, looking at other posts, my TS which debounces form is this:
this.loginForm.valueChanges.debounceTime(500).subscribe(form => {
console.log(form, this.loginForm);
});
Now, the console logs are actually debouncing. But, the validation message does not debounce. It shows up straight away the message.
Is there a way to overcome this issue?
Thanks, for stopping by,
I believe the debounceTime will only affect the code you have in the response form => { ... }.
So what you could do is set the validation there:
private loginFormIsValid:boolean;
private emailIsNotValid:boolean;
ngOnInit() {
this.loginForm.valueChanges.debounceTime(500).subscribe(form => {
this.loginFormIsValid = !loginForm.find('email').valid
&& loginForm.find('email').touched;
this.emailIsNotValid = loginForm.controls['email'].dirty
&& !loginForm.controls['email'].valid;
console.log(form, this.loginForm);
});
}
...And then you would use it in you template as follows:
<div class="form-group" [class.error]="!loginFormIsValid">
<div class="input-wrapper">
<input type ="email"
class="form-control"
id="email-input"
placeholder="Email"
formControlName="email">
</div>
<div *ngIf="emailIsNotValid"
class="alert-msg">Email is invalid</div>
</div>
You can take a look at a post on debouncing, it's a good example.

Using angular 1.3 ngMessage for form submission errors

I've gotten an example of form validation working correctly in my app for the login page, looking something like this:
<div class="form-group" >
<label for="password">Password</label>
<input type="password"
id="password"
name="password"
class="form-control"
placeholder="Create password"
ng-model="password"
required
minlength="{{passwordLength}}"
>
<div class="help-block text-danger"
ng-messages="form.password.$error"
ng-if="form.password.$touched || form.$submitted"
>
<div class="text-danger">
<div ng-message="required">A password is required</div>
<div ng-message="minlength" >Password must be at least {{passwordLength}} characters</div>
</div>
</div>
</div>
This works great for "required" and "minlength" checks, which can be done before submission. However after submission, we can get back a 401 for an invalid username/password. Angular 1.3 has an async validaiton concept, but it seems to run before submission, and it seems unreasonable to try to login twice (once just to see if they could and prompt an error)
Is there a reasonable way to use the ng-messages concept to display this post-submission error?
I figured it out. You can just manually validate/invalidate the form:
<div class="help-block text-danger">
<div class="text-danger"
ng-messages="form.password.$error"
ng-if="form.password.$touched || form.$submitted">
<div ng-message="required">Password is required</div>
<div ng-message="minlength">*Password must be at least {{passwordLength}} characters</div>
<div ng-message="correctPassword">Username/Password combination is incorrect</div>
</div>
</div>
and in your controller, on submit:
$scope.login = function(){
$scope.form.password.$setValidity("correctPassword", true);
// ...do some stuff...
$http.post('/someUrl', {msg:'hello word!'})
.success(function(){})
.error(function() {
$scope.form.password.$setValidity("correctPassword", false);
});
}

Categories

Resources