My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
Angular JS —  Cleaner form validation with CSS only

Angular JS —  Cleaner form validation with CSS only

hot JS's photo
hot JS
·Jul 25, 2016

In this post, I will like to show you how to keep your forms validation style DRY and clean.

Let’s start by showing what most of the online tutorials will teach you.

So let’s say we have two required input fields, one for the first name and the second for last name. When the user submits the form, we want to style the invalid input with a red border.

<form name=”$ctrl.form” ng-submit=”$ctrl.submit()” novalidate>
<input type=”text” 
       name=”firstName” 
       ng- model=”$ctrl.user.firstName” 
       ng-class=”{‘has-error’: $ctrl.submitted && $ctrl.form.firstName.$error.required}”
required>
<input type=”text” 
       name=”lastName” 
       ng- model=”$ctrl.user.lastName” 
       ng-class=”{‘has-error’: $ctrl.submitted &&  $ctrl.form.lastName.$error.required}”
required>
</form>
//The controller
class FormsController {

  constructor() {
    this.form = {};
  }

  submit() {
    this.submitted = true;
  }
}

What are the problems with this approach?

  1. The code is not DRY.
  2. We keep adding watchers.
  3. The HTML is verbose.

So how can we do better?

When you submit a form, Angular will add the class “ng-submitted” to the form element. Angular will also add to the invalid inputs the class “ng-invalid”. We can leverage this classes and style with CSS the inputs that are not valid when the form is submitted.

// You can specify only the inputs that you want, this is general rule for all the inputs include submit for example
.ng-submitted input.ng-invalid {
  border: 1px solid red;
}

Now we have one general rule for all the forms in our app.

We can take it step further and make cooler validation with only CSS.

Validate email:

<div class=”form-group email-field error-indication”>
 <input type=”email” 
        name=”email” 
        required 
        ng-model=”$ctrl.user.email”
        class=”form-control”>
 </div>
.ng-submitted.ng-invalid .error-indication::after {
  display:block;
  color: red;
  margin-top: 0.3rem;
  font-size: 0.8rem;
}
.ng-submitted.ng-invalid-email .email-field::after  {
   content: 'This email is not valid';
}

Validate min max length:

<div class=”form-group password-field error-indication”>
 <input type=”password” 
         name=”password” 
         required 
         ng-model=”$ctrl.user.password”
         class=”form-control” 
         pattern=”.{5,10}”>
 </div>
.ng-submitted.ng-invalid-pattern .password-field::after  {
    content: 'Password must be between 5-10 chars';
}

Validate range:

<div class=”form-group number-field error-indication”>
 <input type=”number” 
        name=”age” 
        min=”18" 
        max=”100" 
        ng-model=”$ctrl.user.age” 
        required>
 </div>
.ng-submitted.ng-invalid-min .number-field::after, 
.ng-submitted.ng-invalid-max .number-field::after {
     content: 'Age must be between 18-100';
}

You can play with the code here: demo