AngularJS Form Validation
Validators decide whether a control value is acceptable. Dirty, touched and submitted flags help choose when to explain a failure; those flags are not substitutes for a rule.
How it works
This form requires a code of at least two characters. The handler checks the form’s validity before producing its local preview. The example keeps the submit button active so the refused path can be tested and explained. Disabling an action can help a user, but the underlying operation must still reject invalid input when it is called.
Run the code
AngularJS 1.8.3 is a legacy framework whose official support ended in January 2022. These examples teach maintenance, not a recommendation for a new application. They need a separate local browser page; Bhylu has no AngularJS playground.
In an empty folder save the HTML below as validation.html and the server as lab-server.mjs. Make a vendor folder and save the four pinned libraries there, retaining their MIT notices. With Node 22 or later run node lab-server.mjs validation.html, then open http://127.0.0.1:8136/. Stop that lab before running a different lesson. The server supplies fixed read-only HTTP fixtures; no data is saved and it does not connect to SQL. No PHP, Apache or MySQL configuration changes are needed.
Example
<!doctype html>
<html lang="en" ng-app="repairLab" ng-strict-di>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AngularJS Form Validation</title>
<style>
:root {
font:
18px/1.55 system-ui,
sans-serif;
color: #0f3464;
background: #fff;
color-scheme: light;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
main {
max-width: 50rem;
margin: auto;
padding: 1.2rem;
}
h1 {
font-size: 1.65rem;
}
label {
display: block;
margin: 0.6rem 0;
}
input,
select,
textarea,
button {
font: inherit;
max-width: 100%;
padding: 0.35rem;
margin: 0.2rem;
}
button {
border: 1px solid #034fa0;
border-radius: 0.25rem;
background: #034fa0;
color: white;
}
button:disabled {
opacity: 0.55;
}
output,
[role="status"] {
display: block;
min-height: 1.5rem;
}
table {
border-collapse: collapse;
width: 100%;
}
td,
th {
padding: 0.4rem;
border: 1px solid #a5bbd4;
text-align: left;
}
pre {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
:focus-visible {
outline: 3px solid #0078d4;
outline-offset: 3px;
}
[ng-cloak] {
display: none !important;
}
.marked {
font-weight: 700;
}
.error {
color: #a02424;
}
:root[data-theme="dark"] {
color: #d6e7fb;
background: #061d30;
color-scheme: dark;
}
:root[data-theme="dark"] .error {
color: #ffb4b4;
}
</style>
</head>
<body>
<main ng-controller="DeskController as vm" ng-cloak>
<h1>Community repair desk</h1>
<p>AngularJS 1.8.3 · Legacy maintenance lab · Local demonstration</p>
<form name="repair" ng-submit="vm.submit(repair)" novalidate>
<label
>Request code<input
name="code"
ng-model="vm.request.code"
required
ng-minlength="2" /></label
><button type="submit">Preview code</button>
</form>
<p data-result>{{ vm.message }}</p>
</main>
<script src="/vendor/angular.min.js"></script>
<script>
(function () {
"use strict";
var app = angular.module("repairLab", []);
app.controller("DeskController", [
function () {
var vm = this;
vm.request = { code: "" };
vm.message = "Not submitted";
vm.submit = function (form) {
vm.message = form.$valid
? "Preview " + vm.request.code
: "Check request code";
};
},
]);
})();
</script>
</body>
</html>
Focus on the bindings and controller
This excerpt leaves out the document shell, styles and library files. Use the complete download to run it.
<form name="repair" ng-submit="vm.submit(repair)" novalidate>
<label
>Request code<input
name="code"
ng-model="vm.request.code"
required
ng-minlength="2" /></label
><button type="submit">Preview code</button>
</form>
<p data-result>{{ vm.message }}</p>
<script>
(function () {
"use strict";
var app = angular.module("repairLab", []);
app.controller("DeskController", [
function () {
var vm = this;
vm.request = { code: "" };
vm.message = "Not submitted";
vm.submit = function (form) {
vm.message = form.$valid
? "Preview " + vm.request.code
: "Check request code";
};
},
]);
})();
</script>
Expected result
Not submitted
The test first submits an empty form, then enters RQ-4 and submits again. The invalid control can leave the model undefined under the normal ngModel validation contract, which is another reason not to read its value without checking validity. A trusted service must repeat its own domain checks.