-1

I bet tons of you guys had this issue and it may be called "Javascript implicit global var" or something like that. Basically, I'm trying to write a validation tool and I have a class MIMIRxErrorHandler. It has 2 methods, validate(), which validates all fields, and validateSpecificField(), which validates each field. One strange thing is that in the method validate(), it always throws the following error:

rule is not defined for line: "let fieldName = rule.name;"


Could someone help me get through this? Thanks a lot. The whole code is below:

class MIMIRxErrorHandler {
  constructor(props) {}

  validate(rules) {
    var errorMessages = {};
    for (var i = 0; i < rules.length; i++) {
      let rule = rules[i];
      let fieldName = rule.name;
      const validationResult = this.validateSpecificField(
        rule.value,
        rule.rules
      );
      if (validationResult.length > 0) {
        errorMessages[fieldName] = `${fieldName} ${validationResult.join(",")}`;
      }
    }
    return errorMessages;
  }

  validateSpecificField(value, rules) {
    const isPresence = rules.presence;
    const rangeRule = rules.range;
    const regexRule = rules.regex;
    const otherNotAllowedValuesRule = rule.otherNotAllowedValues;
    var errorMessages = [];
    //  ***  range  ***
    if (isPresence) {
      if (value === null || value === undefined || value === NaN) {
        errorMessages.push(` cannot be blank`);
      }
    }
    if (rangeRule !== null && rangeRule !== undefined) {
      const type = rangeRule.type;
      if (type == "number") {
        value = parseFloat(value);
        if (value > rangeRule.maxLength || value < rangeRule.minLength) {
          errorMessages.push(
            ` between ${rangeRule.minLength} and ${rangeRule.maxLength}`
          );
        }
      } else if (type == "string") {
        value = value.toString();
        if (
          value.length > rangeRule.maxLength ||
          value.length < rangeRule.minLength
        ) {
          errorMessages.push(
            ` between ${rangeRule.minLength} and ${rangeRule.maxLength}`
          );
        }
      }
    }
    if (regexRule !== null && regexRule !== undefined) {
      if (!value.match(regexRule.pattern)) {
        errorMessages.push(regexRule.regexErrorMessage);
      }
    }
    if (otherNotAllowedValuesRule.includes(value)) {
      errorMessages.push(" is invalid");
    }
    return errorMessages;
  }
}

rules = () => {
  return [
    {
      name: "first_name",
      value: "John",
      rules: {
        presence: true,
        range: {
          type: "string",
          minLength: 10,
          maxLength: 200,
        },
        regex: {
          pattern: /^\w+$/,
          regexErrorMessage: " should only be letters",
        },
        otherNotAllowedValues: ["0", ""],
      },
    },
    {
      name: "age",
      value: "23",
      rules: {
        presence: true,
        range: {
          type: "number",
          minLength: 1,
          maxLength: 3,
        },
        regex: {
          pattern: /^\d+$/,
          regexErrorMessage: " should be only digits",
        },
        otherNotAllowedValues: ["0", ""],
      },
    },
  ];
};

var a = new MIMIRxErrorHandler();
console.log(a.validate(this.rules()));
khan
  • 1,466
  • 8
  • 19
Invincible_Pain
  • 491
  • 2
  • 6
  • 17
  • don't use var, use let and const – Kid Apr 08 '20 at 03:34
  • 4
    @O.o—irrelevant. – RobG Apr 08 '20 at 03:41
  • Probably a duplicate of [*Detecting an undefined object property in JavaScript*](https://stackoverflow.com/questions/27509/detecting-an-undefined-object-property). Since it seems *rule* can be undefined, you need to test before accessing any of its properties like `if (rule)` or more strictly `if (typeof rule != 'undefined')`. – RobG Apr 08 '20 at 03:45
  • 1
    Is `rules` a class method? It doesn't appear so in your code. If it is, the `this` context in `a.validate(this.rules())` doesn't refer to `a`. If `rules()` always returns an array, it might be better to set the array to `MIMIRxErrorHandler.rules` and access it via `this` inside of your methods. You might also need to bind your class methods in your constructor. – khan Apr 08 '20 at 03:51
  • good point @khan – Mosia Thabo Apr 08 '20 at 03:55

2 Answers2

1

There are two errors in the code:

  1. const otherNotAllowedValuesRule = rule.otherNotAllowedValues;
    ReferenceError: rule is not defined.
    change:
    const otherNotAllowedValuesRule = rules.otherNotAllowedValues;
  2. if (!value.match(regexRule.pattern)) {
    TypeError: value.match is not a function
    change:
    if (typeof value == 'string' && !value.match(regexRule.pattern)) { errorMessages.push(regexRule.regexErrorMessage); } if (typeof value == 'number' && !value.toString().match(regexRule.pattern)) { errorMessages.push(regexRule.regexErrorMessage); }

NOTE: I am assuming rules is a method of class MIMIRxErrorHandler.

var a = new  MIMIRxErrorHandler()
console.log(a.validate(a.rules()));
Arjun Singh
  • 302
  • 1
  • 12
0

When it comes to using a value created as an item of a list or other objects it's always important to ensure that there's value in them prior to using them in your operations.

Commonly, you test for data using if(rule) which literally checks for value within rule.

Or perhaps before you even get that far, it would also help you to ensure that rules : type [] has values in it by testing if(rules.length > 0 before you try to accesing any of it's items.

Mosia Thabo
  • 4,009
  • 1
  • 14
  • 24