2
votes

Angular 4 template driven validation fails. Is this a known issue, or my bug?

Html:

<div class="form-group">
  <label for="email">Email</label>
  <input type="email" class="form-control" id="email" required 
    [(ngModel)]="model.email" name="email" #email="ngModel" #spy>

  <div>TODO remove: {{spy.className}}</div>
  <div [hidden]="email.valid || email.pristine" class="alert alert-danger">
    Valid email is required
  </div>
</div>

Component class has property: model = new SignupModel('','','','');

CSS:

input:invalid:not(.ng-pristine) {
    border-left: 5px solid #a94442; /* red */
}
input:valid:not(.ng-pristine) {
    border-left: 5px solid #42A948; /* green */
}

When page first loads, you can see email class names: form-control ng-untouched ng-pristine ng-invalid The alert message is hidden due to email.pristine === true

When user starts typing "aa" the class names change: form-control ng-dirty ng-valid ng-touched Now the message is hidden due to email.valid === true However, since "aa" is not a valid email, the left border shows as red via css.

Why does Angular consider email.valid to be true and sets ng-valid class, when the css correctly interprets the input as invalid?

The style class does change to ng-invalid when you remove "aa", correctly interpreting "required" property.

1

1 Answers

2
votes

Solution is to add additional "email" attribute to input tag:

<input type="email" class="form-control" id="email" required email 
    [(ngModel)]="model.email" name="email" #email="ngModel">