skip to Main Content

The following functions are defined in an Angular component:

    handleInput(event) {
        // Validate the input
        if (event.target.value.length >= 8) {
            this.validate(event.target.value);
        }
    }
    // Validation logic for provider NG_VALIDATORS will
    // Logic for NG_VALIDATORS provider, returns validation result to parent form
    /** @internal */
    validate(control) {
        const value = control.value || control;
        if (this.required && value.replace(/s+/g, '').length === 0) {
            this.hasError = this.control.touched || this.control.dirty;
            this.errorText = [{ message: this.requiredErrorMessage }];
            return this.required ? { required: 'date required' } : null;
        }
        if (!value) {
            this.hasError = false;
            return null;
        }
        const [day, month, year] = value.split('.').map(Number);
        if (day && month && year && value.length === 10) {
            const date = new Date(year, month - 1, day);
            const isDateValid = !isNaN(date.getTime()) && date.getFullYear() === year && date.getMonth() + 1 === month && date.getDate() === day;
            this.hasError = !isDateValid || date > this.maxDate || date < this.minDate;
            if (this.hasError) {
                this.hasError = true;
                this.errorText = [{ message: this.validationErrorMessage }];
                return { invalid: 'date invalid' };
            }
        }
        this.hasError = false;
        return null;
    }

This is the corresponding custom input field:


    <input
      #input
      type="text"
      mask="00.00.0000"
      autocomplete="off"
      (input)="handleInput($event)"
      [(ngModel)]="value"
    />


The input field will add with ngx-mask a mask for a date field in DD.MM.YYYY format.

Problem:

When the component is rendered, the following error is thrown:

ERROR TypeError: value.split is not a function

For this line of code: const [day, month, year] = value.split('.').map(Number);

I already tried to fix it with

if (!value) {
            this.hasError = false;
            return null;
        }

The error is shown when the component is rendered of if a string was entered in the input field and then the input has been deleted (empty input field).

2

Answers


  1. There is no need to call the validate function on the input event. It will be called automatically by angular internals. So focus on calling the onChange method that you registered and also mark the control as touched.

    onChange = (quantity) => {};
    
    onTouched = () => {};
    
    registerOnChange(onChange: any) {
      this.onChange = onChange;
    }
    
    registerOnTouched(onTouched: any) {
      this.onTouched = onTouched;
    }
    
    markAsTouched() {
      if (!this.touched) {
        this.onTouched();
        this.touched = true;
      }
    }
    
    // change events from the textarea
    private handleInput(event: any) {
        this.markAsTouched();
        this.onChange(event.target.value);
    }
    

    Creating custom form controls with validation – Tutorial

    Login or Signup to reply.
  2. Problem Explanation:

    In your validate method, you are assuming that value is always a string, but when the input field is empty or undefined, value may be null, undefined, or an object, and that’s why calling .split('.') causes the error. The error occurs specifically when:

    • The input is empty on initial render (because value is probably undefined or null).

    • The input is cleared (the value becomes ""), and split is called on an empty string.

    Solution:

    You need to ensure that value is always a string before calling .split. You can handle this by adding a check to ensure value is a non-empty string before attempting to split it. Also, it’s a good idea to validate that value is a string type in the validate method.

    Here’s how you can fix the issue:

    Updated validate method:

    validate(control) {
        const value = control.value || control;
    
        // Ensure value is a non-empty string
        if (typeof value !== 'string') {
            this.hasError = false;
            return null;  // Return null if value is not a string (e.g. undefined, null, or object)
        }
    
        if (this.required && value.replace(/s+/g, '').length === 0) {
            this.hasError = this.control.touched || this.control.dirty;
            this.errorText = [{ message: this.requiredErrorMessage }];
            return this.required ? { required: 'date required' } : null;
        }
    
        if (!value) {
            this.hasError = false;
            return null;
        }
    
        const [day, month, year] = value.split('.').map(Number);  // Now this line is safe as `value` is guaranteed to be a string
    
        if (day && month && year && value.length === 10) {
            const date = new Date(year, month - 1, day);
            const isDateValid = !isNaN(date.getTime()) && date.getFullYear() === year && date.getMonth() + 1 === month && date.getDate() === day;
            this.hasError = !isDateValid || date > this.maxDate || date < this.minDate;
            if (this.hasError) {
                this.hasError = true;
                this.errorText = [{ message: this.validationErrorMessage }];
                return { invalid: 'date invalid' };
            }
        }
    
        this.hasError = false;
        return null;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search