PremKumar
PremKumar

Reputation: 1354

Using Custom validators in angular reactive form

I'm trying to use custom validator to compare if the end time is greater than the start time.

code:

function timeValidator(): ValidatorFn {
  return (control: AbstractControl): { [key: string]: boolean } | null => {
      if (control.value !== undefined && (isNaN(control.value) || control.get('fromTime').value > control.get('toTime').value)) {
          return { 'ageRange': true };
      }
      return null;
  };
}

From formgroup

toTime: new FormControl(null, [Validators.required, timeValidator(this.fromTime,this.toTime)]),

I'm getting a error once I run this like: Cannot read property 'value' of null on the line if (control.value !== undefined && (isNaN(control.value) || control.get('fromTime').value > control.get('toTime').value))

I need some help in fixing this. Thank you

Upvotes: 0

Views: 2082

Answers (4)

user28543826
user28543826

Reputation: 1

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

export function uniqueChildConditionValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!Array.isArray(control.value)) {
      return null; // If the control value is not an array, no validation needed
    }

    const mainObjects = control.value;

    // Iterate over each main object to check its child conditions
    for (let i = 0; i < mainObjects.length; i++) {
      const mainObj = mainObjects[i];

      // Ensure the current main object has child conditions to check
      if (mainObj.childCondition && mainObj.childCondition.length > 0) {
        const seenChildConditions = new Set<string>();

        // Check each child condition for duplication
        for (const child of mainObj.childCondition) {
          const childConditionKey = `${child.field}-${child.condition}-${child.conditionText}`;

          // Check if the child condition matches the parent condition
          const parentConditionKey = `${mainObj.field}-${mainObj.condition}-${mainObj.conditionText}`;
          if (childConditionKey === parentConditionKey) {
            return { conditionMismatch: `Child condition in main object ${i + 1} matches the parent condition.` };
          }

          // Check if the child condition has been seen before (duplicate check)
          if (seenChildConditions.has(childConditionKey)) {
            return { conditionMismatch: `Child condition ${childConditionKey} is duplicated in main object ${i + 1}.` };
          }

          // Add the child condition to the set of seen conditions
          seenChildConditions.add(childConditionKey);
        }
      }
    }

    return null; // No issues found
  };
}

Upvotes: 0

tyujhty
tyujhty

Reputation: 1

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

export function uniqueChildConditionValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!Array.isArray(control.value)) {
      return null; // If the control value is not an array, no validation needed
    }

    const mainObjects = control.value;

    // Iterate over each main object to check its child conditions
    for (let i = 0; i < mainObjects.length; i++) {
      const mainObj = mainObjects[i];
      
      // Ensure the current main object has child conditions to check
      if (mainObj.childCondition && mainObj.childCondition.length > 0) {
        const seenChildConditions = new Set<string>();

        // Check each child condition for duplication
        for (const child of mainObj.childCondition) {
          const childConditionKey = `${child.field}-${child.condition}-${child.conditionText}`;

          // Check if the child condition matches the parent condition
          const parentConditionKey = `${mainObj.field}-${mainObj.condition}-${mainObj.conditionText}`;
          if (childConditionKey === parentConditionKey) {
            return { conditionMismatch: `Child condition in main object ${i + 1} matches the parent condition.` };
          }

          // Check if the child condition has been seen before (duplicate check)
          if (seenChildConditions.has(childConditionKey)) {
            return { conditionMismatch: `Child condition ${childConditionKey} is duplicated in main object ${i + 1}.` };
          }

          // Add the child condition to the set of seen conditions
          seenChildConditions.add(childConditionKey);
        }
      }
    }

    return null; // No issues found
  };
}

Upvotes: 0

user28527180
user28527180

Reputation: 1

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

export function uniqueMainChildConditionValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!Array.isArray(control.value)) {
      return null; // Not an array, so we don't need to validate
    }

    const mainObjects = control.value;

    for (let i = 0; i < mainObjects.length; i++) {
      const mainObj = mainObjects[i];
      
      // Check each main object's child conditions
      if (mainObj.childCondition && mainObj.childCondition.length > 0) {
        for (const child of mainObj.childCondition) {
          if (
            mainObj.field === child.field &&
            mainObj.condition === child.condition &&
            mainObj.conditionText === child.conditionText
          ) {
            return { conditionMismatch: `Main object ${i + 1} has matching properties with a child condition.` };
          }
        }
      }

      // Check if the current main object matches any other main object
      for (let j = 0; j < mainObjects.length; j++) {
        if (i !== j) { // Ensure we are not comparing the same object
          const otherMainObj = mainObjects[j];
          if (
            mainObj.field === otherMainObj.field &&
            mainObj.condition === otherMainObj.condition &&
            mainObj.conditionText === otherMainObj.conditionText
          ) {
            return { conditionMismatch: `Main object ${i + 1} has matching properties with main object ${j + 1}.` };
          }
        }
      }
    }

    return null; // No issues found
  };
}

Upvotes: 0

terahertz
terahertz

Reputation: 3511

Your custom validator should be put at FormGroup level not FormControl level. Also you should pass the function in as an argument, meaning without the () brackets because timeValidator is a callback function. () tells the js engine to execute the function. But what you want is pass in the function as an argument, so it could be executed later.

either

constructor(private fb: FormBuilder){}
...
this.form = this.fb.group({
    fromTime: [''],
    toTime: ['']
}, { validator: timeValidator})

OR

 form = new FormGroup({
     toTime: new FormControl(null),
     fromTime: new FormControl(null),
 }, { validator: timeValidator})

Your custom validator also shouldn't be returning a function. It should be returning a name:boolean key-value pair. E.g. isEndGTStart: true or null if false

E.g.

export function timeValidator(fg: FormGroup){
    const fromTime = fg.get("fromTime").value;
    const toTime = fg.get("toTime).value;

    return toTime > fromTime ? { isEndGTStart: true } : null
}

Upvotes: 1

Related Questions