Varun
Varun

Reputation: 3735

Angular 6 Reactive Forms Custom Validator Error Displayed from it's OWN data

I have a FormArray in a FormGroup and each of the FormArray has multiple FormGroup's and can add them dynamically.

I have a Custom Validator where it checks with all the data in each of the FormArray to validate the repetition of data. There's an issue with it, the single FormGroup in FormArray is comparing it to all the data in the FormArray and is returning True since the FormGroup exists inside of the FormArray

StackBlits link: https://stackblitz.com/edit/angular-custom-validator-defaultdata

Problem Steps: Click on Additional Assignment => Select Position, Department and Location same as the previous row. => You'll see the error, "Same Job data " => Now change the value of the Position to something else => No Error => Change the value in the Pay Rate input => You see the error, "Same Job data " > Because it's comparing the changed row to the data from the Form Data which will definitely return True.

Is there any way to restrict the error from throwing itself when it's checking its own data.?

I'm only checking the similarity between Position, Department, and Location.

for (let assign of this.additionalAssign) {
      const fg = new FormGroup({
        "payRate": new FormControl(assign.jobRate, Validators.required),
        "position": new FormControl(assign.position, Validators.required),
        "location": new FormControl(assign.location, Validators.required),
        "department": new FormControl(assign.department, Validators.required)
      }); 
      fg.validator = this.jobDataValidator.bind(this);
      this.addPay.push(fg);
    }

Validator:

jobDataValidator(control: FormControl): {[s: string]: boolean} {
    let value = this.getJobLocDeptValidity(control);
    if(value.length > 0 && control.dirty){
      return {'sameJobData': true};
    }
    return null;
  }

  getJobLocDeptValidity(control: FormControl):any[] {
    let additionalAssignments = this.additionalAssignmentsForm.value.payArray;
    let test = additionalAssignments.filter(item =>  !!control.value.position && item.position === control.value.position && !!control.value.department && item.department === control.value.department && !!control.value.location && item.location === control.value.location);
    return test;
  }

Image 1: New Row (3rd) data same as previous one(2nd) => Error Displayed Same data as previous one

Image 2: Change the Position select value and the Error Disappears Position changed and Error Disappears

Image 3: Enter some number in Pay Rate input and the Error displays again. Input payrate changes and Error Appears

Upvotes: 1

Views: 2038

Answers (3)

Sunil
Sunil

Reputation: 11243

Your implementation looks perfectly fine except the check condition. Since you don't have any unique id for row its difficult to match if the record is existing one or now.

However you are lucky enough to have reference of all required object. You can check if the Object matched or not.

Just add one more condition in validation part

control !== item 

Below is the changed code -

  getJobLocDeptValidity(control: FormControl):any[] {

    let additionalAssignments = this.additionalAssignmentsForm.value.payArray;
    let test = additionalAssignments.filter(item =>  
    control !== item && !!control.value.position && item.position === control.value.position && !!control.value.department && item.department === control.value.department && !!control.value.location && item.location === control.value.location);
    return test;
  }

Update

Since you have index and per your comment, below check works.

control.index !== item.i

Upvotes: 2

Eva
Eva

Reputation: 19

You can try excluding the payRate value from the validator like so:

jobDataValidator(control: FormControl): {[s: string]: boolean} {
    let value = this.getJobLocDeptValidity(control);
    if(value.length > 0 && control.dirty  && !control.value.payRate){
      return {'sameJobData': true};
    }
    return null;
  }

Upvotes: 0

Ajay Ojha
Ajay Ojha

Reputation: 390

I have forked your sample application and did some minor changes in the code. now it is working as expected. Please see on stackblitz.

I have done three changes which are listed below :

  1. You don't have any uniqueid on row level, I have added as index of your 'this.addPay' length. See Line number : 57 and 75.
  2. applied condition in the 'getJobLocDeptValidity' method to check index of current control and filter index should not be same and did some other changes.

Here are the code changes of your getJobLocDepValidity.

 getJobLocDeptValidity(control: FormControl):any[] {
    let additionalAssignments = this.additionalAssignmentsForm.value.payArray;
    let test = additionalAssignments.filter(item => {
if(control.value.index != item.index){
return (item.payRate == control.value.payRate && item.position == control.value.position && item.department == control.value.department && item.location == control.value.location)
}
return false;
    } );
    return test;
  }

@Sunil I would suggest, please try to give a correct answer and test it before giving your inputs, So someone can implement easily without any buggy code.

Upvotes: 1

Related Questions