Forms & Validation

AngularJS treats a <form> as more than a plain HTML element — naming it turns it into an object you can inspect from your controller, and combining ng-model with standard HTML validation attributes gives you working validation with no JavaScript validation logic written by hand.

A validated field

Standard HTML attributes like required and type="email" work together with ng-model — AngularJS watches them and applies CSS classes reflecting the field's current validity:

HTML signup.html
<form ng-app="" name="signupForm" novalidate>
  <input
    name="email"
    type="email"
    ng-model="userEmail"
    required>
  <span ng-if="signupForm.email.$invalid && signupForm.email.$touched">
    Please enter a valid email.
  </span>
</form>
Rendered behavior
Typing "not-an-email" and then clicking away from the field:
• the <input> gets the CSS classes ng-invalid and ng-dirty automatically
• "Please enter a valid email." appears, since $invalid and $touched are both true
Typing a real address like "maya@example.com" instead:
• the classes flip to ng-valid
• the warning message disappears

novalidate on the <form> turns off the browser's own built-in validation UI so AngularJS's version is the only one shown. signupForm.email is how you reach that specific field's state from anywhere in the template — $invalid, $valid, $touched, and $pristine are properties AngularJS maintains on it automatically as the user interacts with the field.

Checking overall form validity

The form itself exposes the same kind of state, aggregated across every field inside it — useful for disabling a submit button until everything required is filled in correctly:

HTML submit-button.html
<button type="submit" ng-disabled="signupForm.$invalid">
  Sign up
</button>
Rendered behavior
The button is disabled as long as any required field in signupForm is
invalid or empty, and becomes clickable the instant every field passes.

ng-disabled binds the button's disabled attribute to an expression — here, signupForm.$invalid, which is true if any field inside the form is currently invalid. No click handler had to check form state manually; the binding does it continuously.

Course complete: that covers AngularJS end to end — bootstrapping a page with ng-app, the core directives (ng-repeat, ng-if, ng-model), how expressions and two-way binding actually work, controllers and the $scope object that ties them to a template, organizing an app into modules, formatting output with filters, sharing logic through services like $http, and validating forms without hand-written validation code. You now have what it takes to read, and safely extend, a real-world AngularJS codebase — and if you're starting something new instead, the modern Angular course on this site picks up where this one's ideas were eventually rebuilt.