3

I'll try to explain the problem step by step.

I wrote some custom validators in AngularJS both as directives and as a service. Here's the code:

//validators.service.ts

@Injectable()
export class ValidatorsService {

  constructor() { }

  email():ValidatorFn {
    return (control: FormControl) => {
      if (!isNullOrUndefined(control.value) && control.value !== '') {
        const isValid = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(control.value);
        if (isValid) return null;
        return { emailValidator: { valid: false } }
      }

      return null
    };
  }
}


//email.directive.ts
@Directive({
  selector: '[appEmailValidator]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useClass: EmailValidatorDirective,
      multi: true
    }
  ]
})
export class EmailValidatorDirective implements Validator {

  validator: ValidatorFn;
  
  constructor(private validatorsService: ValidatorsService) {
    this.validator = this.validatorsService.email()
  }

  validate(c: FormControl) {
    return this.validator(c);
  }

}

which i use like this:

<input 
  pInputText 
  id="email" 
  name="email" 
  appEmailValidator 
  [(ngModel)]="mymodel" 
  required>

or like this:

//*.component.html

<input 
  type="email" 
  pInputText 
  id="email"
  formControlName="email" name="email">


//*.component.ts

ngOnInit() {
        this.actorForm = new FormGroup({
            email: new FormControl('', [this.validatorsService.email(), Validators.required]),
        });
    }

It works perfectly in terms of Regex: "my@email.com" gets accepted whereas "my@email.long" does not.

The problem comes when i type more characters (especially over 26): Chrome gets stuck, I can't enter any new character, my CPU usage goes to 100% and it basically crashes, even reloading the page becomes impossible. This doesn't happen with Safari for example.

So:

• I tried to convert my service into simple functions, nothing has changed.

• I removed the PrimeNg directive thinking it might cause the problem, nothing.

• I removed the directive and I tried to use the HTML pattern, nothing.

• I removed the entire ngModel directive and it worked, so it has to do with Angular somehow. Also, it works by binding the event (change)=inputChanged($event) and updating the model with:

inputChanged(e){
  this.model = event.target.value
}

• Then, I tried to remove just the event binding: [ngModel]="model" using HTML input pattern, nope.

• I updated my Angular version to the latest (I'm using version 4.3.1), nothing.

• I changed my regex into /.+/ and it worked, and, even if it's useless, i got that the problem was related to my regex and ngModel.

Therefore, I read these questions:

HTML input pattern not working

Regex on Chrome pattern input validation

and even if i don't have any errors and, as I said, it works initially, I converted every \. into . , again, nothing has changed.

What's wrong with my regex? Have you ever encountered this problem? Do you have a workaround?

I'd like to use Angular features but it seems unlikely.

UPDATE

It seems I'm not the only one who had to deal with this error:

https://github.com/angular/angular/issues/12753

Angularjs input field is getting stuck on typing in google chrome

but it's still unsolved.

• I tried to debounce the input as someone in github has suggested, it doesn't work.

• I literally copied and pasted the same Regex Angular uses as email validator:

/^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

and it worked.

Is my regex inefficient? If that were the case, it wouldn't work in other browsers either, isn't it?

UPDATE

• I bound the input and keyup events and moved my logic in JS (without HTML pattern, but I think it doesn't matter). It doesn't work, even with 1s of debounce. Yet, as i said, the change event works.

• I tried with myRegex.test(myLongString) just to understand whether this has to deal with events or not. Surprisingly, chrome gets stuck anyway. I don't know why the change event works. Maybe, I haven't tested it properly.

The only way I solved this is by modifying my regex:

/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

(https://emailregex.com/)

which is way better than the Angular one.

Just for reference, I post some tests I made.

valida => valid

invalida => invalid

New working regex (emailregex.com)

New working regex (emailregex.com)

My old (not working) regex New working regex (emailregex.com)

Angular regex

Angular Regex

pb15
  • 31
  • 3

0 Answers0