I am going to implement the validation in angular 4.
I've already have a solution but need simple and clean code.
Here is my code.
mobile-auth.component.ts
this.appForm = fb.group({
'otp': ['', Validators.compose([Validators.required, ValidationService.digit4Validator])],
});
validation.service.ts
...
static digit4Validator(control) {
if (control.value) {
if (control.value.match(/^\d+/) && control.value.length === 4) {
return null;
} else {
return {'invalid4DigitCode': true};
}
}
}
...
If you have any good solution please let me know.
Your validator should only validate that it's a valid number. Angular already provides a minlength validator which should be used instead.
You can refactor your validator as this:
export function digitValidator(length: number): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
if (control.value) {
if (control.value.match(/^\d+/) && control.value.length === length) {
return null;
} else {
return {`invalidDigitCode, length should be ${length}`: true};
}
}
};
}
...
this.appForm = fb.group({
'otp': ['', Validators.compose([Validators.required,
Validators.digitValidator(4)])
...
Or you can use like this:
this.appForm = fb.group({
'otp': ['', Validators.compose([Validators.required,
Validators.minLength(4),
Validators.maxLength(4)])],
});
Related
In the component, I use formBuilder for Angular Reactive Forms
I get the example code from this post
min = 10;
max = 20;
ngOnInit() {
this.loginForm = new FormGroup({
email: new FormControl(null, [Validators.required]),
password: new FormControl(null, [Validators.required, Validators.maxLength(8)]),
age: new FormControl(null, [ageRangeValidator(this.min, this.max)])
});
}
The custom validation is defined in function ageRangeValidator
function ageRangeValidator(min: number, max: number): ValidatorFn {
return (control: AbstractControl): { [key: string]: boolean } | null => {
if (control.value !== undefined && (isNaN(control.value) || control.value < min || control.value > max)) {
return { 'ageRange': true };
}
return null;
};
}
In case, min and max are got from api call. How can to pass them to function custom validator?
FormControl API provide setValidators method. Which you can use to set Validator dynamically. Inside subscribe call back you can call setValidators something like this:
Try this:
..subscribe((result)=>{
this.age.setValidators([ageRangeValidator(result.min,result.max)]);
this.loginForm.get('age').updateValueAndValidity();
})
Example
I prefer the answer of Chellappan, but if you are going to change the value of max and min along the live of app angular, another way is that the function validator belong to the component and bind to this
//this function IN the component
ageRangeValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: boolean } | null => {
if (control.value !== undefined && (isNaN(control.value) ||
control.value < this.min ||control.value > this.max)
) {
return { ageRange: true };
}
return null;
};
}
//and when create the component
age: new FormControl(15, [this.ageRangeValidator().bind(this)]) //<--see the bind(this)
I have two dates like one arrivaldate and exitdate .Trying to add custom validation like the exit date not be less than arrival date if its less show error message.Please find the below code.
component.ts file:
arrivalDate: ['', [Validators.required, this.validateArrivalDate()]],
exitDate: ['', [Validators.required, this.validateExitDate()]],
validateExitDate(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
if (this.currentTravelFormGroup !== undefined) {
//const arrivalDate = control.value;
const exitDate = this.currentTravelFormGroup.controls['exitDate'].value;
const arrivalDate = this.currentTravelFormGroup.controls['arrivalDate'].value
if (exitDate <= arrivalDate) return { requiredToDate: true };
}
};
}
validateArrivalDate(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
if (this.currentTravelFormGroup !== undefined) {
const exitDate = this.currentTravelFormGroup.controls['exitDate'].value;
const fexitDate = new Date(exitDate);
const arrivalDate = this.currentTravelFormGroup.controls['arrivalDate'].value;
if (fexitDate <= arrivalDate) return { requiredFromDate: true };
}
};
}
In Html I'm showing error message:
<mat-error *ngIf="currentTravelFormGroup.get('arrivalDate').hasError('requiredFromDate')">Please provide a valid arrival date</mat-error>
<input class="form-control bgColor" [matDatepicker]="pickerExitDateFromGermany" placeholder="MM/DD/YYYY" [min]="minStartDateFutureTravel" [max]="maxStartDateFutureTravel" formControlName="exitDate" id="exitDate" readonly (click)="pickerExitDateFromGermany.open()"
[ngClass]="{ 'is-invalid': submitted && travelDet.exitDate.errors }">
<mat-datepicker #pickerExitDateFromGermany></mat-datepicker>
<mat-error *ngIf="currentTravelFormGroup.get('exitDate').hasError('requiredToDate')">Please provide a valid exitdate</mat-error>
The condition works and shows the error message respectively for exit and arrival date but.
if arrival date is 11/11/2019 and exit date is 10/11/2019(error message will be shown below exit input field).If i change arrival date as 08/11/2019 (arrival date
what is the problem .how do i solve it.Please help
I solved this problem by clear ,setting and updating values after validateExitDate() and validateArrivalDate() methods.
validateExitDate(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
if (this.currentTravelFormGroup !== undefined) {
//const arrivalDate = control.value;
const exitDate = this.currentTravelFormGroup.controls['exitDate'].value;
const arrivalDate = this.currentTravelFormGroup.controls['arrivalDate'].value
if (exitDate <= arrivalDate) return { requiredToDate: true };
else{
this.currentTravelFormGroup.get('exitDate ').clearValidators();
this.currentTravelFormGroup.get('exitDate').updateValueAndValidity();
}
}
};
}
Same with Arrivaldate function.:)
Hi I am trying to set/ take away custom validators for different elements in a form array that can change around, so far what I have tried to do is create a switch statement and loop through all of the input types that are set so I could set the validation rule as well as send a message to the user if the rule isn't met. The problem I am having is the form is initialized before the form data is set.
So my question is how can I loop through the array and set the validation rules. If someone could let me know if im along the right tracks with using a switch statement but have code in the wrong place or if there is a different and better approach it would be most helpful thank you
export class ReactiveComponent implements OnInit {
public form: FormGroup;
public fieldList: any;
types: Array<any>;
formData: any;
Param: string;
setData: any;
formLabelNames: any;
get contactFormGroup() {
return this.form.get('inputs') as FormArray;
}
constructor(
private route: ActivatedRoute,
private fb: FormBuilder,
private api: FormService,
private notifiy: NotificationService,
private auth: AuthService,
private router: Router) { }
ngOnInit() {
this.form = this.fb.group({
name: ['', Validators.compose([Validators.required])],
organization: ['', Validators.compose([Validators.required])],
inputs: this.fb.array([this.createForm()])
});
this.route.paramMap.subscribe(params => {
this.Param = params.get('id');
this.getForm(this.Param);
});
// set fieldslist to this field
this.fieldList = this.form.get('inputs') as FormArray;
}
// formgroup
createForm(): FormGroup {
return this.fb.group({
type: ['', Validators.compose([Validators.required])],
name: ['', Validators.compose([Validators.required])],
value: ['', this.validators()]
});
}
getForm(id) {
this.api.getForm(id).subscribe(
(data: any) => this.setForm(data)
);
}
getFieldsFormGroup(index): FormGroup {
const formGroup = this.fieldList.controls[index] as FormGroup;
return formGroup;
}
getContactsFormGroup(index): FormGroup {
const formGroup = this.fieldList.controls[index] as FormGroup;
return formGroup;
}
setForm(data) {
const d = data.results;
this.setData = d;
this.formLabelNames = d[0].fields;
this.form.patchValue({
name: [d[0].form_name],
organization: [d[0].org],
});
this.form.setControl('inputs', this.setExistingFields(d[0].fields));
}
setExistingFields(fields: any): FormArray {
const formArray = new FormArray([]);
this.fieldList = formArray;
fields.forEach(f => {
formArray.push(this.fb.group({
name: f.name,
type: f.type,
value: f.value
}));
});
return formArray;
}
/* This is where I have tried to create a switch statement but I get a undefined error because the setform function is being called after this one */
validators() {
this.formLabelNames.type.forEach((field: any) => {
switch (field.type) {
case 'email':
}
});
}
submit() {
if (this.form.valid) {
const formId = this.Param;
const local = this.auth.decodePayload();
const userId = local.sub;
this.router.navigateByUrl('/dashboard');
this.api.sendForm(this.form.value, formId, userId).subscribe();
this.form.reset();
} else {
this.notifiy.showFailure('Form is not valid', 'Error');
}
}
}
You have several problems, as far as I can judge:
You don't initialize neither the formControls nor the formArray correctly inside of you formGroup. It should rather look like this:
this.form = this.fb.group({
name: new FormControl( "", {validators: [Validators.required]}),
organization: new FormControl( "", {validators: [Validators.required]}),
inputs: this.fb.array([new FormControl(), new FormControl()]),
});
Besides: What is the point of using a formArray when it consists of only one formGroup?
Off course you can set the validators for any abstractControl be it a formControl or a formGroup. For the array it would look like something like this:
this.formArray.controls.map((ctrl) => {
ctrl.setValidators([Validators.required, Validators.email]);
});
It doesn't matter where in the component class you put your method. Though it surely matters when that method is invoked!
Im using mat-stepper of Angular Material design library.
I use 3 separate FormGroups. I would send informations to database using httpClient method, for that I have created an interface :
export interface NouveauProjet {
leadProj: String ;
nomProj: String;
descProj: String;
besProj: Number;
pers: [Personnes];
Backlog: [Fonctionnalite]
}
export interface Personnes {
name: String;
poste:String
}
export interface Fonctionnalite {
fonctionnalite: String;
userStory: String
}
In my component file I create forms and nouveauProject variable that will contain my values .
export class AjoutProjetComponent implements OnInit {
isLinear = false;
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;
thirdFormGroup: FormGroup;
nouveauProjet: NouveauProjet;
constructor(
private _formBuilder: FormBuilder,
private ajoutProj: AjoutprojService
) {}
ngOnInit() {
console.log();
this.firstFormGroup = this._formBuilder.group({
leadProj: ["", Validators.required],
nomProj: ["", Validators.required],
descProj: ["", Validators.required],
besProj: ["", Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
pers: this._formBuilder.array([this.createItem()])
});
this.thirdFormGroup = this._formBuilder.group({
backlog: this._formBuilder.array([this.createFonct()])
});
}
createItem(): FormGroup {
return this._formBuilder.group({
name: ["", Validators.required],
poste: ["", Validators.required]
});
}
createFonct(): FormGroup {
return this._formBuilder.group({
fonctionnalite: ["", Validators.required],
userStory: ["", Validators.required]
});
}
I call my service and before I concatenate formGroup.value.
addProjet() {
this.nouveauProjet =
this.firstFormGroup.value +
this.secondFormGroup.value +
this.thirdFormGroup.value;
console.log(this.nouveauProjet);
this.ajoutProj
.addProj(this.nouveauProjet)
.toPromise()
.then(res => {
console.log(res.json);
});
}
}
In html file I call addProject function then I print {{nouveaProjet | json}} value I get this :
"[object Object][object Object][object Object]"
How to print all values ?
Update: this.firstFormGroup.value, this.secondFormGroup.value, this.thirdFormGroup.value gives in order :
Object cannot be concatenated with + so you could try:
Old way:
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
this.nouveauProjet = __assign(this.firstFormGroup.value, this.secondFormGroup.value, this.thirdFormGroup.value);
Using ES6 spread operator:
this.nouveauProjet = {
...this.firstFormGroup.value,
...this.secondFormGroup.value,
...this.thirdFormGroup.value
};
I am using Ionic 2 with Angular 2 beta 11.
I have a custom validator that works perfectly. However, I now need to add another custom validation method, but can't seem to work out how to pass a parameter to it.
As you can see below, I have a custom validation function:
ValidationService.userNameExists(control, this.employeeService)
'control' does not exist
How do I pass the control (FormControl) to the userNameExists function? Or, I need to pass the field value (value of username).
Thanks
register.ts
constructor(private nav: NavController, private builder: FormBuilder, employeeService: EmployeeService) {
this.employeeService = employeeService;
this.registerForm = builder.group({
'username': ['', [Validators.required, Validators.minLength(5), Validators.maxLength(55), ValidationService.userNameValidator, ValidationService.userNameExists(control, this.employeeService)]],
'password1': ['', [Validators.required, Validators.minLength(5), Validators.maxLength(45), ValidationService.passwordValidator]],
'password2': ['', [Validators.required, Validators.minLength(5), Validators.maxLength(45), ValidationService.passwordValidator]]
}, { 'validator': ValidationService.matchPassword('password1', 'password2') }
);
}
'control' does not exist
ValidationService.ts
public static userNameExists(control: FormControl, employeeService: EmployeeService): any {
return (control: FormControl) => {
let userNameInput = control.value;
console.log('userNameExists: '+control.value);
let promise: Promise<EmployeeModel> = employeeService.getEmployeByUserName(userNameInput);
promise.then((employeeModel: EmployeeModel) => {
if (employeeModel.userName === userNameInput) {
return { userNameExists: true };
} else {
return null;
}
});
}
}
Remember that when you are instantiating FormControl/FormGroup, you are passing the validation function in, not calling it. Change your username declaration as following:
'username': ['',
[Validators.required,
Validators.minLength(5),
Validators.maxLength(55),
ValidationService.userNameValidator,
(control) => ValidationService.userNameExists(control, this.employeeService)]]