Form validation (JS)
A minimal HTML5 validation wrapper for ng-form. Native checkValidity() drives the rules; the script paints the states and the messages. Link ng_form.js. For the markup itself see Form.
Once mounted, the script sets novalidate on the form and takes over: on submit every field is checked (an invalid form never submits); after the first interaction each field re-validates live on blur (text) or change (select/check). No rules to configure — use the native attributes: required, type="email", minlength, min/max, pattern…
Live demo
Press Submit with empty fields: the invalid fields turn red with a generated message (ng-field-error + ng-help). Fix them and the state flips to ng-field-success. Every control type takes part: inputs, number, select, textarea, radios and the required checkbox.
<form class="ng-form" id="fv-demo" action="#">
<div class="ng-field mb-16">
<label class="ng-label ng-label-required" for="fv-name">Name</label>
<input type="text" class="ng-input" id="fv-name" name="name" required minlength="3">
</div>
<div class="ng-field mb-16">
<label class="ng-label ng-label-required" for="fv-email">Email</label>
<input type="email" class="ng-input" id="fv-email" name="email" required>
</div>
<div class="ng-field mb-16">
<label class="ng-label" for="fv-age">Age</label>
<input type="number" class="ng-input" id="fv-age" name="age" min="18" max="120">
</div>
<div class="ng-field mb-16">
<label class="ng-label ng-label-required" for="fv-plan">Plan</label>
<select class="ng-select" id="fv-plan" name="plan" required>
<option value="">Choose…</option>
<option value="starter">Starter</option>
<option value="pro">Pro</option>
<option value="enterprise">Enterprise</option>
</select>
</div>
<div class="ng-field mb-16">
<label class="ng-label ng-label-required" for="fv-msg">Message</label>
<textarea class="ng-textarea" id="fv-msg" name="message" rows="3" required minlength="10"></textarea>
<div class="ng-help">At least 10 characters.</div>
</div>
<div class="ng-field mb-16">
<label class="ng-label">Contact me by</label>
<label class="ng-check-nexi classic">
<input type="radio" name="contact" value="email" checked>
<span class="ng-check-box"></span> Email
</label>
<label class="ng-check-nexi classic">
<input type="radio" name="contact" value="phone">
<span class="ng-check-box"></span> Phone
</label>
</div>
<div class="ng-field mb-16">
<label class="ng-check-nexi bolder">
<input type="checkbox" name="terms" required>
<span class="ng-check-box"></span> I accept the terms
</label>
</div>
<div class="ng-form-actions">
<button type="submit" class="ng-btn ng-btn-primary">Submit</button>
</div>
</form>
How it works
| Mount | Every ng-form is enhanced automatically; novalidate suppresses the browser bubbles. |
|---|---|
| Rules | Native HTML5 attributes (required, type, minlength, pattern…) via checkValidity(). |
| States | The wrapper ng-field gets ng-field-error or ng-field-success. |
| Messages | A ng-help with the native validation message is generated inside the field (data-ng-generated) and removed when the field becomes valid. |
| Live | Re-validation on blur for text controls, on change for selects and checks. |
| Submit | An invalid form calls preventDefault() — it never reaches the server. |
API
Exposed on each form element:
const form = document.querySelector('.ng-form');
form.ngValidate(); // validate every field, paint states → boolean
form.ngReset(); // clear all states and generated messages
form.ngSerialize(); // typed plain object from named controls
ngSerialize()
Returns a plain object built from every control with a name (buttons excluded). Values are typed by control — not the flat strings of FormData:
| text / email / textarea | String. |
|---|---|
number / range | Number, or null when empty. |
| checkbox | true / false (checked state). |
| radio group | Value of the checked radio, or null if none. |
| select | Selected option value (null if none); multiple → array of values. |
| file | Array of file names. |
| date / time / color | String value, or null when empty. |
Filled with the demo form above, the output looks like this:
{
"name": "Jane Doe", // text → string
"email": "jane@acme.com", // email → string
"age": 34, // number → Number (null if empty)
"plan": "pro", // select → option value (null if none)
"message": "Hello there!", // textarea → string
"contact": "email", // radio → checked value (null if none)
"terms": true // checkbox → boolean
}
Try it live — fill the demo form, then:
// press the button…
Anatomy
ng-form ng-field ng-field-error ng-field-success ng-help[data-ng-generated] API
form.ngValidate() form.ngReset() form.ngSerialize()