I'm having a Contact form in Angular using a Reactive form. The form contains firstName
, lastName
and an Array of address
. Each address formgroup contains a checkbox, if the checkbox is checked, validation of the State text box mandatory is needed, along with min and max char length.
I have written a custom validator namely "stateValidator
" and I tried to get the sibling element "isMandatory
" but I am not able to get the control.
I tried the following approach
control.root.get('isMandatory');
- Its returningnull
control.parent.get('isMandatory');
- Its throwing exception
I found some links in stackoverflow, but there is no answer available and some answers are not giving solutions, for example the code above: control.root.get('isMandatory');
I got this from one of the video tutorials but nothing worked.
The plete working source code is available in StackBlitz:
appponent.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators, AbstractControl } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './appponent.html',
styleUrls: [ './appponent.css' ]
})
export class AppComponent {
name = 'Angular';
public userForm: FormGroup;
constructor(private _fb: FormBuilder) {
this.userForm = this._fb.group({
firstName: [],
lastName: [],
address: this._fb.array([this.addAddressGroup()])
});
}
private addAddressGroup(): FormGroup {
return this._fb.group({
street: [],
city: [],
state: ['', this.stateValidator],
isMandatory: [false, [Validators.required]]
});
}
get addressArray(): FormArray {
return <FormArray>this.userForm.get('address');
}
addAddress(): void {
this.addressArray.push(this.addAddressGroup());
}
removeAddress(index: number): void {
this.addressArray.removeAt(index);
}
stateValidator(control: AbstractControl): any {
if(typeof control === 'undefined' || control === null
|| typeof control.value === 'undefined' || control.value === null) {
return {
required: true
}
}
const stateName: string = control.value.trim();
const isPrimaryControl: AbstractControl = control.root.get('isMandatory');
console.log(isPrimaryControl)
if(typeof isPrimaryControl === 'undefined' || isPrimaryControl === null||
typeof isPrimaryControl.value === 'undefined' || isPrimaryControl.value === null) {
return {
invalidFlag: true
}
}
const isPrimary: boolean = isPrimaryControl.value;
if(isPrimary === true) {
if(stateName.length < 3) {
return {
minLength: true
};
} else if(stateName.length > 50) {
return {
maxLength: true
};
}
} else {
control.setValue('');
}
return null;
}
}
appponent.html
<form class="example-form" [formGroup]="userForm">
<div>
<mat-card class="example-card">
<mat-card-header>
<mat-card-title>Users Creation</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="primary-container">
<mat-form-field>
<input matInput placeholder="First Name" value="" formControlName="firstName">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Last Name" value="" formControlName="lastName">
</mat-form-field>
</div>
<div formArrayName="address">
<div class="address-container" *ngFor="let group of addressArray.controls; let i = index;"
[formGroupName]="i">
<fieldset>
<legend>
<h3>Address: {{i + 1}}</h3>
</legend>
<mat-checkbox formControlName="isMandatory">Mandatory</mat-checkbox>
<div>
<mat-form-field>
<input matInput placeholder="Street" value="" formControlName="street">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="City" value="" formControlName="city">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="State" value="" formControlName="state">
</mat-form-field>
</div>
</fieldset>
</div>
</div>
<div class="form-row org-desc-parent-margin">
<button mat-raised-button (click)="addAddress()">Add more address</button>
</div>
</mat-card-content>
</mat-card>
</div>
</form>
<mat-card class="pre-code">
<mat-card-header>
<mat-card-title>Users Information</mat-card-title>
</mat-card-header>
<mat-card-content>
<pre>{{userForm.value | json}}</pre>
</mat-card-content>
</mat-card>
Kindly assist me how to get the sibling abstract control in the custom validator method.
I tried the code which was specified in the following couple of answers
isPrimaryControl = (<FormGroup>control.parent).get('isMandatory')
It's throwing an error ERROR Error: too much recursion
. Kindly assist me how to fix this.
I'm having a Contact form in Angular using a Reactive form. The form contains firstName
, lastName
and an Array of address
. Each address formgroup contains a checkbox, if the checkbox is checked, validation of the State text box mandatory is needed, along with min and max char length.
I have written a custom validator namely "stateValidator
" and I tried to get the sibling element "isMandatory
" but I am not able to get the control.
I tried the following approach
control.root.get('isMandatory');
- Its returningnull
control.parent.get('isMandatory');
- Its throwing exception
I found some links in stackoverflow, but there is no answer available and some answers are not giving solutions, for example the code above: control.root.get('isMandatory');
I got this from one of the video tutorials but nothing worked.
The plete working source code is available in StackBlitz: https://stackblitz./edit/angular-custom-validators-in-dynamic-formarray
app.ponent.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators, AbstractControl } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.ponent.html',
styleUrls: [ './app.ponent.css' ]
})
export class AppComponent {
name = 'Angular';
public userForm: FormGroup;
constructor(private _fb: FormBuilder) {
this.userForm = this._fb.group({
firstName: [],
lastName: [],
address: this._fb.array([this.addAddressGroup()])
});
}
private addAddressGroup(): FormGroup {
return this._fb.group({
street: [],
city: [],
state: ['', this.stateValidator],
isMandatory: [false, [Validators.required]]
});
}
get addressArray(): FormArray {
return <FormArray>this.userForm.get('address');
}
addAddress(): void {
this.addressArray.push(this.addAddressGroup());
}
removeAddress(index: number): void {
this.addressArray.removeAt(index);
}
stateValidator(control: AbstractControl): any {
if(typeof control === 'undefined' || control === null
|| typeof control.value === 'undefined' || control.value === null) {
return {
required: true
}
}
const stateName: string = control.value.trim();
const isPrimaryControl: AbstractControl = control.root.get('isMandatory');
console.log(isPrimaryControl)
if(typeof isPrimaryControl === 'undefined' || isPrimaryControl === null||
typeof isPrimaryControl.value === 'undefined' || isPrimaryControl.value === null) {
return {
invalidFlag: true
}
}
const isPrimary: boolean = isPrimaryControl.value;
if(isPrimary === true) {
if(stateName.length < 3) {
return {
minLength: true
};
} else if(stateName.length > 50) {
return {
maxLength: true
};
}
} else {
control.setValue('');
}
return null;
}
}
app.ponent.html
<form class="example-form" [formGroup]="userForm">
<div>
<mat-card class="example-card">
<mat-card-header>
<mat-card-title>Users Creation</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="primary-container">
<mat-form-field>
<input matInput placeholder="First Name" value="" formControlName="firstName">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Last Name" value="" formControlName="lastName">
</mat-form-field>
</div>
<div formArrayName="address">
<div class="address-container" *ngFor="let group of addressArray.controls; let i = index;"
[formGroupName]="i">
<fieldset>
<legend>
<h3>Address: {{i + 1}}</h3>
</legend>
<mat-checkbox formControlName="isMandatory">Mandatory</mat-checkbox>
<div>
<mat-form-field>
<input matInput placeholder="Street" value="" formControlName="street">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="City" value="" formControlName="city">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="State" value="" formControlName="state">
</mat-form-field>
</div>
</fieldset>
</div>
</div>
<div class="form-row org-desc-parent-margin">
<button mat-raised-button (click)="addAddress()">Add more address</button>
</div>
</mat-card-content>
</mat-card>
</div>
</form>
<mat-card class="pre-code">
<mat-card-header>
<mat-card-title>Users Information</mat-card-title>
</mat-card-header>
<mat-card-content>
<pre>{{userForm.value | json}}</pre>
</mat-card-content>
</mat-card>
Kindly assist me how to get the sibling abstract control in the custom validator method.
I tried the code which was specified in the following couple of answers
isPrimaryControl = (<FormGroup>control.parent).get('isMandatory')
It's throwing an error ERROR Error: too much recursion
. Kindly assist me how to fix this.
- If you have to put validations which include multiple formControls, consider adding the Validator to the formGroup instead of a single formControl. – Sachin Gupta Commented Apr 11, 2019 at 8:04
- @SachinGupta - My primary aim of this question is how to get the sibling control over another control. – B.Balamanigandan Commented Apr 12, 2019 at 11:24
-
As stated in my answer, you can use
(<FormGroup>control.parent).get('isMandatory')
. However, depending on where you accesscontrol.parent
, there might be a chance that the value isundefined
so you have to put proper checks – Sachin Gupta Commented Apr 12, 2019 at 11:26 -
I'm getting an error
ERROR Error: too much recursion
if I add the codeisPrimaryControl = (<FormGroup>control.parent).get('isMandatory')
– B.Balamanigandan Commented Apr 12, 2019 at 11:35 -
1
ment the
control.setValue('')
– Sachin Gupta Commented Apr 12, 2019 at 11:51
2 Answers
Reset to default 4You may need to cast the parent to FormGroup
, try using :
if(control.parent) {
(<FormGroup>control.parent).get('isMandatory')
}
You can get the value of isMandatory
from Form control like this, i have changed your stateValidator
method to basically typecast the control
to concrete sub class then from the controls
array you can get the formControls
stateValidator(control: AbstractControl): any {
let mandatory:boolean=false;
if(control.parent){
console.log('control',<FormGroup>control.parent.controls.isMandatory.value);
mandatory=<FormGroup>control.parent.controls.isMandatory.value;
}
if((typeof control === 'undefined' || control === null
|| typeof control.value === 'undefined' || control.value === null)&& mandatory) {
debugger;
return {
required: true
}
}
const stateName: string = control.value.trim();
let isPrimaryControl: AbstractControl=null;
if(control.parent){
isPrimaryControl=<FormGroup>control.parent.controls.isMandatory;
console.log(isPrimaryControl)
}
if(typeof isPrimaryControl === 'undefined' || isPrimaryControl === null||typeof isPrimaryControl.value === 'undefined' || isPrimaryControl.value === null) {
return {
invalidFlag: true
}
}
const isPrimary: boolean = isPrimaryControl.value;
if(isPrimary === true) {
if(stateName.length < 3) {
return {
minLength: true
};
} else if(stateName.length > 50) {
return {
maxLength: true
};
}
} else {
control.setValue('');
}
return null;
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744712072a4589402.html
评论列表(0条)