angular 6 :- Reactive form validation is not working propery - javascript

need regarding angular 6 reactive form validation, I have studied from official angular website
I want to validate my form and display the different error message to different error
Component code
this.pinForm = new FormGroup({
'defaultPin': new FormControl(this.pin.oldPin, [
Validators.required,
Validators.minLength(4)
])
});
Html code
<form [formGroup]="pinForm" #formDir="ngForm">
<div class="form-group">
<label for="defaultPin">Default Pin</label>
{{formDir.valid}}
<input type="text" name="defaultPin" class="form-control" id ="defaultPin" aria-describedby="defaultPin" placeholder="Please enter your old Pin"
formControlName = "defaultPin" />
<small id="defaultPin" class="form-text text-muted">Check your Email address for default pin.</small>
{{defaultPin}}
<div *ngIf="defaultPin.invalid && (defaultPin.dirty || defaultPin.touched)"
class="alert alert-danger">
enter code here
<div *ngIf="defaultPin.errors.required">
Name is required.
</div>
<div *ngIf="defaultPin.errors.minlength">
Name must be at least 4 characters long.
</div>
</div>
</div>
But when I run I'm getting this error
ERROR TypeError: Cannot read property 'invalid' of undefined
at Object.eval [as updateDirectives] (AddPinComponent.html:21)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:10756)
at checkAndUpdateView (core.js:10153)
at callViewAction (core.js:10394)
at execComponentViewsAction (core.js:10336)
at checkAndUpdateView (core.js:10159)
at callViewAction (core.js:10394)
at execEmbeddedViewsAction (core.js:10357)
at checkAndUpdateView (core.js:10154)
at callViewAction (core.js:10394)
Please help me

You are using reactive form and Template-driven together.
Use Only Reactive form.
Do changes in your files. (modify as per your requirement).
Component.Html
<form [formGroup]="pinForm">
<div class="form-group">
<label for="defaultPin">Default Pin</label>
<input type="text" name="defaultPin" class="form-control" id="defaultPin" aria-describedby="defaultPin" placeholder="Please enter your old Pin"
formControlName="defaultPin" />
<span class="text-danger" *ngIf="pinForm.controls['defaultPin'].hasError('required') && (pinForm.controls['defaultPin'].dirty || pinForm.controls['defaultPin'].touched)">This field is required</span>
</div>
</form>
Component.ts
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
export class AppComponent {
pinForm: FormGroup;
constructor(fb: FormBuilder) {
this.pinForm = fb.group({
'defaultPin': [null, Validators.required],
});
}
}
module.ts
// Import ReactiveFormModule in your module.ts file
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
#NgModule({
imports: [ FormsModule, ReactiveFormsModule ],
If you still have problem refer Stackblitz

When you write formControlName = "defaultPin" you provides name for FormControl but in order to access such properties as invalid, errors etc you have to FormControl instance from FormGroup like:
pinForm.get('defaultPin')
So simply add the following getter to your component:
get defaultPin() {
return this.pinForm.get('defaultPin')
}

You need to reference your pinForm to get its controller:
*ngIf="!pinForm.controls.defaultPin.valid && (pinForm.controls.defaultPin.dirty || pinForm.controls.defaultPin.touched)"
So, this is what your form is supposed to look like:
<form [formGroup]="pinForm" #formDir="ngForm">
<div class="form-group">
<label for="defaultPin">Default Pin</label>
{{formDir.valid}}
<input type="text" name="defaultPin" class="form-control" id ="defaultPin" aria-describedby="defaultPin" placeholder="Please enter your old Pin"
formControlName = "defaultPin" />
<small id="defaultPin" class="form-text text-muted">Check your Email address for default pin.</small>
{{defaultPin}}
<div *ngIf="!pinForm.controls.defaultPin.valid && (pinForm.controls.defaultPin.dirty || pinForm.controls.defaultPin.touched)")"
class="alert alert-danger">
enter code here
<div *ngIf="pinForm.controls.defaultPin.errors.required">
Name is required.
</div>
<div *ngIf="pinForm.controls.defaultPin.errors.minlength">
Name must be at least 4 characters long.
</div>
</div>
</div>
Also, you should initiate your formGroup in your components ngOnInit():

Related

Angular enabling and disabling component or element based on input changes

How do we do this in angular, make button disabled by default if email address is invalid , If email is invalid get started button will enable and the user can click get started button ,
after the user click get started button it will disabled again and will only enable again if user changes the email input and if the new email input is valid , vice versa.
I already have the checked and the form controls , but is there a cleaner way to do this in angular? Thanks.
#html code
<mat-form-field class="full-width" appearance="fill" style="margin-top: 20px;">
<mat-label>Email</mat-label>
<input type="email" matInput autocomplete="emailAddress" matInput formControlName="emailAddress" />
<mat-error *ngIf="modelForm.get('emailAddress').hasError('email')">
Email is in invalid format.
</mat-error>
<mat-error *ngIf="modelForm.get('emailAddress').hasError('required')">
Email is required.
</mat-error>
</mat-form-field>
</div>
<div style="text-align:right;margin-top: 19.0px;">
<button click)="getStarted()" [disabled]="!modelForm.get('emailAddress')?.valid" mat-flat-button color="primary"
class="v-btn-sml" id="get-started-button">
Get Started
</button>
</div>
#ts validation code
ngOnInit(): void {
this.initFormGroup();
}
initFormGroup() {
this.modelForm = this.formBuilder.group({
id: [this.model.id || 0],
emailAddress:[this.model.emailAddress,[Validators.required, Validators.email]],
});
}
Angular has built in validators you can use, combining it with the ReactiveFormsModule you have to import in your app.module.ts.
In your typescript file you can do it like:
formGroup: FormGroup;
private model: { id: number; emailAddress: string } = {
id: 1,
emailAddress: ''
};
ngOnInit() {
this.formGroup = new FormGroup({
id: new FormControl(this.model.id),
email: new FormControl(this.model.emailAddress, [Validators.email])
});
}
And than in your html file you can access this formControls valid/invalid state.
<form [formGroup]="formGroup">
<input type="text" formControlName="email">
<button type="button" [disable]="form?.get('emailAddress').invalid">
</form>

Binding Input Controls to different elements inside FormArray

I'm facing the following issue and I am unsure how to solve it, here is a minimal example https://stackblitz.com/edit/angular-ivy-vwq15f .
In this example I am trying to bind the two input field (name and gender)
<div formArrayName="formArray" class="column">
<div [formGroupName]="inspectedForm">
<h1>Input field for Person {{inspectedForm +1}}</h1>
<label for="name">name</label>
<input formControlName="name" type="text" class="input" placeholder="Name">
<label for="gender">gender</label>
<input formControlName="gender" >
</div>
dynamically to an element inside a FormArray. By clicking on the person (Person #1) I want to be able to change the specific properties that person with the provided input fields. The solution should be capable of selecting a person to edit the properties WITHOUT generating new Input fields.
I guess I must somehow bind to the formControlName of the specific Input like [formControlName="blabla" but I am very unsure.
Thanks a lot in advance :)
My html looks like this
<form [formGroup]="parentForm">
<div *ngFor="let rule of arrayForm.controls; let i = index" class="button is-fullwidth not-clickable">
<button (click)="changeInspectedElement(i)">Person {{i +1}}</button>
</div>
<button (click)="addElement()">Add Element</button>
<div formArrayName="formArray" class="column">
<div [formGroupName]="inspectedForm">
<h1>Input field for Person {{inspectedForm +1}}</h1>
<label for="name">name</label>
<input formControlName="name" type="text" class="input" placeholder="Name">
<label for="gender">gender</label>
<input formControlName="gender" >
</div>
</div>
</form>
<p>
{{parentForm.value | json}}
</p>
My .ts looks like this
import { Component } from '#angular/core';
import { FormArray, FormBuilder, FormGroup } from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
parentForm: FormGroup
inspectedForm: number = 0
constructor(private _fb: FormBuilder,) {
this.parentForm = this._fb.group({
formArray: this._fb.array([
this.createArrayForm()
])
})
}
createArrayForm() {
return this._fb.group({
name: [''],
gender: ['']
})
}
changeInspectedElement(index) {
let value = this.arrayForm.value[index]
this.inspectedForm = index
}
addElement() {
this.arrayForm.push(this.createArrayForm())
}
get arrayForm() {
return this.parentForm.get('formArray') as FormArray
}
}
Please let me know if there is anything unclear about my question.
You has a FormArray of FormGroup, so, you can create a function that return this formGroup
getGroup(index)
{
return (this.parentForm.get('formArray') as FormArray).at(index) as FormGroup
//or using your function arrayForm
//return this.arrayForm.at(index) as FormGroup
}
So, you can feel free to use this function in html to indicate FormGroup
<div [formGroup]="getGroup(inspectedForm)">
<input formControlName="name" type="text" class="input" placeholder="Name">
<input formControlName="gender" >
Yes, it's not necesary use FormArray. futhermore, in the .html has no reference to parentForm. Well the only you need is that your buttons change the variable inspectedForm.
<button (click)="inspectedForm=i">Person {{i +1}}</button>
your forked stackblitz

angular 5, reactive form- resetting a required form control does not reset the required error under the input

In the template I have a form that is opened by pressing on a button-
<form [formGroup]="person"
(ngSubmit)="onSubmitNewPerson()"
#formDirective="ngForm">
<mat-form-field>
<input matInput formControlName="firstName" required>
</mat-form-field>
<mat-form-field>
<input matInput formControlName="lastName" #last required>
</mat-form-field>
</form>
In the component I have this code-
#ViewChild('formDirective') formDirective: FormGroupDirective;
this.person = this.formBuilder.group({
lastName: ['', Validators.required],
firstName: ['', Validators.required]
});
After closing the button I run this function-
this.formDirective.resetForm();//hack that I saw in some question
this.person.reset();
but after openning again the form, I immediatly see the red error under the input.
I also tried this-
this.person.get('firstName').markAsUntouched();
this.person.get('lastName').markAsUntouched();
this.person.get('firstName').markAsPristine();
this.person.get('lastName').markAsPristine();
But this does not work also.
Any idea how to fix it?
I used the following once when I wanted to reset the validators:
this.person.get('firstName').clearValidators();
this.person.get('firstName').updateValueAndValidity();
Simply remove required from your html template and if you want to display error message on focus out than try this to show different error message.
this is html template:
<div class="form-group">
<label for="name" class="form-control-label">
*Amount:
</label>
<input type="number" name="amount" class="form-control" [formControl]="form.controls['amount']">
<div>
<small *ngIf="form.controls['amount'].hasError('required') && form.controls['amount'].touched" class="text-danger">
Please enter an amount.
</small>
<small *ngIf="form.controls['amount'].hasError('min') && form.controls['amount'].touched" class="text-danger">
Your amount must be at least 0.01.
</small>
<small *ngIf="form.controls['amount'].hasError('max') && form.controls['amount'].touched" class="text-danger">
Your amount cannot exceed 999999.99.
</small>
</div>
This is component.ts
import { FormGroup, FormBuilder, Validators} from '#angular/forms';
constructor(private fb: FormBuilder) { }
this.form = this.fb.group({
amount: [null, Validators.compose([Validators.required, Validators.min(0.01), Validators.max(999999.99)])],
});
Although this question is slightly old,
This answer may help people who have this issue.
If this problem occurs in the Angular material mat-stepper, you can see the solution offered for this question.
(That why some respondents were unable to reproduce the problem)

Angular ReferenceError : Calling typescript function from html form or button

So I'm pretty new to using Angular and I have a new Angular component, one TS file and one HTML file. In the HTML File, I have a form that is supposed to call a function in the corresponding typescript file when the submit button is pressed. Seems simple, but I'm constantly getting the following error :
Uncaught ReferenceError: validateLogin is not defined
at :4200/HTMLInputElement.onclick (http:/localhost:4200/validateLogin();?email=email%40lol.com&password=password:13:283)
onclick # validateLogin();?email=email%40lol.com&password=password:13
VM569:1 Uncaught ReferenceError: validateLogin is not defined
at :1:1
Two ReferenceErrors, one for the attempt with onclick and once for the attempt with the action attribute in form. On submit, I want the div to disappear, and the text "Success" to display. Here is the two files :
import { Component } from '#angular/core';
import { NullAstVisitor } from '#angular/compiler';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'TaManagementApp';
toggleLoginHTML = true;
constructor() {
this.toggleLoginHTML = true;
}
validateLogin() {
// if ()
this.toggleLoginHTML = false;
}
}
And
<!--The content below is only a placeholder and can be replaced.-->
<div *ngIf=toggleLoginHTML>
<div style="text-align:center">
<h1>
TA Management System
</h1>
</div>
<button onclick='validateLogin()'></button>
<div style="text-align:center">
<form action="javascript:validateLogin()">
Email: <input type="email" name="email" value="email"><br>
Password: <input type="password" name="password" value="password"><br>
<input type="submit" value="Submit" onclick='validateLogin()'>
</form>
</div>
</div>
<div *ngIf=!toggleLoginHTML>
<h1>
Success
</h1>
</div>
Any insight for a beginner would be appreciated, thank you!
Like user184994 and qiAlex said, you should use Angular built in click binding by using (click)="validateLogin()" instead of onclick.
However I wanted to suggest you to try an take a look at the Angular Reactive Form Guide in which they explain fairly well how to implement a straightforward binding between your form and your model and possibly build very complex forms.
Also take a look at the Form Validation Guide for some deeper information on how to validate your form inputs.
Instead of
<button onclick='validateLogin()'></button>
...
<input type="submit" value="Submit" onclick='validateLogin()'>
Try
<button (click)="validateLogin()"></button>
...
<input type="submit" value="Submit" (click)="validateLogin()">

TypeError: Cannot read property 'value' of undefined in Angular 4

I am coming to the error in Angular 4. (Angular-CLI), that says:
TypeError: Cannot read property 'value' of undefined. So, I am new to Angular 4 coming from Angular 1. So, I will be thankful for your help. Thanks in advance.
Here is my code.
app.component.html
<!-- using semantic-ui -->
<form class="ui large form segment">
<h3 class="ui header">Add a link</h3>
<!-- added the title -->
<div class="field">
<label for="title">Title:</label>
<input name="title" #newtitle>
</div>
<!-- added the link -->
<div class="field">
<label for="link">Link:</label>
<input name="link" #newLink>
</div>
<!--added the button -->
<button (click)="addArticle(newTitle, newLink)" class="ui positive right floated button">
Submit Link
</button>
</form>
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
addArticle(title: HTMLInputElement, link: HTMLInputElement):
boolean {
console.log(`Adding article title: ${title.value}
and link: ${link.value}`);
return false;
}
}
You casing of the reference variable and the parameter passed do not match. Change <input name="title" #newtitle> to <input name="title" #newTitle> since your are calling addArticle with newTitle with a capital T.

Categories