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,}))$/
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)
Angular regex