AngularJS + TypeScript: how to implement validation

2 minute read

Preface

AngularJs supports all kinds of simple client-side validation. The simplest is data-ng-required which basically says a UI element must be filled in before the form is valid. I am picking up where I left off in my previous post – I am going to make the the phone input screen have validation.

Adapting the view

First of all we are going to tweak the view a little. This is just standard AnguarJS stuff, nothing TypeScript specific here yet:

<div>
  <div>
    Phones
    <div data-ng-repeat="phone in listOfPhones">
      <div>Name: {{phone.name}}; screen size: {{phone.screenSize}}"</div>
    </div>
  </div>

  <button data-ng-click="phoneController.doLoadPhones()">Load phones from server</button>
  <br /><br />
  Add a new phone<br />
  <div data-ng-form="phoneform" class="css-form">
    <label for="name" style="width:40px">Name</label>
    <input id="name" type="text" data-ng-model="newPhone.name"
           data-ng-required="true" /><br />
    <label for="name" style="width:40px">Size</label>
    <input id="screensize" type="text" data-ng-model="newPhone.screenSize"
           data-ng-required="true" /><br />
    <button data-ng-click="phoneController.doSavePhone()"
            data-ng-disabled="!phoneController.canSave()">
      Save
    </button>
  </div>
</div>

I have underlined and written in red what is new:

  • A wrapper div with a form name and a css class
  • data-ng-required attribute, one on each field
  • A data-ng-disabled attribute on the button that will enable/disable it when the input is not valid.

Adapting the scope

Just like anormal AngularJS (based on JavaScript), the scope will now be extended with a property named “phoneform” – for that is how we called the form. So we need to adapt the IPhoneScope like this:

/// <reference path="../models/iphone.ts" />
module App.Scope {
    "use strict";

    export interface IPhoneScope {
        listOfPhones: Models.IPhone[];
        newPhone: Models.IPhone;
        phoneform: ng.IFormController
    }
}

And once again we now have the advantage of a typed object.

Adapting the controller

This is also very simple: we need to create the canSave method. So in the PhoneController we add:

public canSave(): boolean {
    return this.$scope.phoneform.$valid;
}

And that is basically most of what we need to do.

Adding some feedback css

Now to have some visual feedback to see if things are valid or not, we use (again) a standard AngularJS trick. In the view we have added the class “css-form” to the form. So we open the Site.css file in the content folder and add the following css:

.css-form input.ng-invalid.ng-dirty {
    background-color: #FA787E;
}

.css-form input.ng-valid.ng-dirty {
    background-color: #78FA89;
}

Testing the validation

If you run the app (after emptying your cache) you will notice you cannot click the save button initially:

image

If you enter phone name, the field will become greenish. If you type something in the screen size field and then delete it again, the field will become reddish, and the button is still disabled.

image

Only when both fields are filled in the save button is enabled

image

An interesting way to mess up validation – or a bug?

According to numerous samples I saw, you don’t need to write data-ng-required=”true”. Just entering data-ng-required (or plain ng-required) should work as well. It does – your field is invalid when it is empty. Trouble is, if you enter data and then delete it again, the field stays valid – and the form too, and you can hit the save button with one empty field. I have no idea if that is a bug in the version of AnguarJS I use, or if this recently has been changed – but please make sure you write data-ng-required=”true”

Demo solution can be found here