Directive guides
Learn AngularTS directives by the job they perform before using the individual directive reference pages.
Directives are easier to learn by role than by name. Start here when you want to
understand how AngularTS extends HTML, then use the Directives
reference for individual attributes and API
details.
Learning path
- Overview: how directives are
discovered, compiled, linked, and prioritized.
- Data Binding: directives
that synchronize scope data with text, HTML, classes, styles, and form
controls.
- Structural Directives:
directives that add, remove, repeat, switch, include, or protect DOM
sections.
- Forms: validation, model options,
form state, and messages.
- HTTP Directives: declarative
requests and Server-Sent Events from HTML.
- Animation Directives: CSS
hooks and animation-specific attributes.
- Advanced Directives: workers,
WebAssembly, channels, DOM references, accessibility, and event helpers.
Reference lookup
When you already know the directive name, use the per-directive
reference. The reference keeps pages small
and specific, while this section keeps the conceptual grouping that helps new
users build a mental model.
1 - Advanced directives: workers, WASM, channels, viewport
AngularTS advanced directives for Web Workers, WebAssembly, lazy loading, event channels, DOM references, and accessibility — all declarative in HTML.
AngularTS ships several advanced directives that expose modern browser APIs —
Web Workers, WebAssembly, Intersection Observer, and custom event channels —
directly in HTML without requiring JavaScript. These directives are registered
as part of the core ng module and are available in every AngularTS
application.
Controller and scope directives
ng-controller
Attaches a controller function to a section of the DOM, creating a new child
scope populated by the controller.
<div ng-controller="TodoController as ctrl">
<p>{{ ctrl.title }}</p>
</div>
.controller('TodoController', ['$scope', function($scope) {
$scope.title = 'My Todos';
}]);
ng-scope
Assigns a stable name to the current scope so debugging tools and integration
code can find it later. The name is required. ng-scope does not create a child
or isolate scope.
<div ng-controller="UserController" ng-scope="userPanel">
<p>Hello {{ user.name }}</p>
</div>
ng-init
Initializes scope variables inline in the template. Best suited for simple
one-off values or prototyping.
<div ng-init="name = 'World'; count = 0">
Hello {{ name }}, count is {{ count }}
</div>
Tip: Prefer controllers or services over ng-init for any real
application logic. ng-init is ideal for zero-JS demos and quick prototypes.
DOM reference directives
ng-el
Use ng-el when you only need the native DOM element. It is the simple DOM
reference API and is usually the clearest choice for canvas, focus management,
layout measurement, and pointer-driven UI.
<section ng-controller="BoardController as $ctrl">
<canvas ng-el="$ctrl.boardEl"></canvas>
</section>
function BoardController() {
this.boardEl = null;
}
ng-el="$ctrl.boardEl" stores the element on the controller. Use this form with
controller-as syntax.
For simple scope shorthand, pass a bare name:
<canvas ng-el="boardEl"></canvas>
If the value is omitted, AngularTS uses the element id.
<canvas id="board" ng-el></canvas>
ng-ref
Use ng-ref when you need a component or directive controller reference, or
when you need to assign the reference to a full expression such as
$ctrl.child.
<search-box ng-ref="$ctrl.search"></search-box>
<button ng-click="$ctrl.search.clear()">Clear</button>
By default, ng-ref reads the component or element-directive controller when
one exists, and falls back to the DOM element.
ng-ref-read is not a standalone directive. It only changes what ng-ref
assigns.
<canvas ng-ref="$ctrl.boardEl" ng-ref-read="$element"></canvas>
<my-widget ng-ref="$ctrl.resizeHandle" ng-ref-read="resizeHandle"></my-widget>
Use ng-ref-read="$element" only when you specifically need the DOM element
through an assignable expression. For the common DOM-only case, prefer ng-el.
function BoardController() {
this.boardEl = null;
}
Event and communication directives
ng-channel
Subscribes to a named event channel (backed by $eventBus). When an event is
published on the channel, the expression is evaluated.
<div>Latest: {{ lastNotification }}</div>
ng-listener
Attaches a DOM event listener to the element using the native addEventListener
API — without the overhead of Angular’s event directive wiring.
<div>Scroll-tracked content</div>
ng-inject
Injects a named service directly into the scope, making it accessible in the
template without a controller.
<div ng-inject="$http">
<!-- $http is now available in this scope -->
</div>
ng-viewport
Uses the browser’s Intersection Observer API to run expressions when an element
enters or leaves the viewport. Ideal for below-the-fold loading, lazy request
triggers, analytics markers, and canvas/chart initialization.
<div
ng-viewport
on-enter="loadComments($entry)"
on-leave="visible = false"
data-viewport-threshold="0.5"
data-viewport-margin="200px 0px"
>
<div ng-repeat="comment in comments">{{ comment.text }}</div>
</div>
Use data-viewport-once when the enter expression should run only once:
<div ng-viewport data-viewport-once on-enter="loadOnce($entry)"></div>
ng-viewport
Supported attributes:
| Attribute | Description |
|---|
on-enter | Expression evaluated when the element intersects the viewport. |
on-leave | Expression evaluated when the element stops intersecting. |
data-viewport-threshold | Intersection threshold, such as 0.5 or 0, 0.5, 1. |
data-viewport-margin | Root margin passed to IntersectionObserver, such as 200px 0px. |
data-viewport-once | Disconnects the observer after the first enter callback. |
on-enter and on-leave receive $entry and $entries locals from the
Intersection Observer callback.
ng-cloak
Prevents the browser from briefly displaying uncompiled template syntax
({{ }}) before AngularTS bootstraps. Add to the root element or any element
with interpolation.
<div ng-cloak>
<p>Hello {{ user.name }}</p>
</div>
Note: Always include the CSS rule [ng-cloak] { display: none; } in your
stylesheet when using ng-cloak.
Web Workers and WebAssembly
ng-worker
Runs a JavaScript file in a Web Worker and binds the result back to scope. The
worker communicates via postMessage.
<div
ng-worker="/workers/sort.js"
data-params="{ items: largeList }"
on-result="sortedItems = $result"
>
<div ng-repeat="item in sortedItems">{{ item.name }}</div>
</div>
ng-worker
- Type:
string - Required: yes
Path to the Web Worker JavaScript file.
Use an empty ng-worker with data-handle="name" to reuse a worker registered
through app.worker(name, script). Shared handles are application-owned rather
than terminated with the directive scope.
data-params
Data to pass to the worker as the message payload.
on-result
Expression evaluated when the worker posts a result. $result contains the
worker’s response.
Worker results are not inserted as HTML when this expression is absent.
data-request
- Type:
boolean data attribute
Use the standard correlated request protocol instead of consuming every stream
message. This is the preferred mode for shared workers.
interval
Re-send the params to the worker on a millisecond interval.
throttle
Throttle worker invocations to at most once per N milliseconds.
The worker file uses standard onmessage / postMessage:
var sorted = e.data.items.slice().sort((a, b) => a.name.localeCompare(b.name));
postMessage(sorted);
};
ng-wasm
Loads a WebAssembly module and makes its
WasmResource available on
scope.
<div ng-wasm src="/wasm/math.wasm" as="math"></div>
<p>
Result: {{ math.status === 'ready' ? math.exports.add(3, 4) : 'Loading...' }}
</p>
ng-wasm
- Type:
string - Required: yes
Path to the .wasm file to load.
as
Scope property name to assign the
WasmResource to. Defaults to
wasm. The reserved object keys __proto__, constructor, and prototype are
rejected.
Transclusion
ng-transclude
Used inside custom directive templates to mark where transcluded content should
be inserted.
return {
transclude: true,
template: '<div class="panel"><ng-transclude></ng-transclude></div>'
};
});
<my-panel>
<p>This content is transcluded into the panel.</p>
</my-panel>
Non-bindable sections
ng-non-bindable
Prevents AngularTS from compiling or interpolating a subtree. Use this for
displaying raw Angular syntax as documentation or code examples.
<pre ng-non-bindable>
{{ this will not be interpolated }}
ng-repeat="item in items"
</pre>
Aria directives
AngularTS automatically manages ARIA attributes for accessibility. These
directives are applied alongside their functional counterparts:
| Directive | ARIA attribute managed |
|---|
ng-disabled | aria-disabled |
ng-checked | aria-checked |
ng-readonly | aria-readonly |
ng-required | aria-required |
ng-show / ng-hide | aria-hidden |
ng-model | aria-value*, role |
The $aria service and module config let you configure which ARIA attributes
are automatically managed:
angular.createModule('app', []).config({
$aria: {
ariaDisabled: true,
ariaChecked: true,
ariaReadonly: true,
ariaRequired: true,
ariaHidden: true,
ariaValue: true,
tabindex: true,
},
});
Event directives
AngularTS generates event directives for all common DOM events. They all follow
the ng-<eventname>="expression" pattern:
| Directive | DOM event |
|---|
ng-click | click |
ng-dblclick | dblclick |
ng-focus | focus |
ng-blur | blur |
ng-keydown | keydown |
ng-keyup | keyup |
ng-mouseenter | mouseenter |
ng-mouseleave | mouseleave |
ng-mousemove | mousemove |
ng-mouseover | mouseover |
ng-mousedown | mousedown |
ng-mouseup | mouseup |
ng-submit | submit (on forms) |
ng-cut | cut |
ng-copy | copy |
ng-paste | paste |
ng-load | load |
The expression is evaluated in the current scope. $event refers to the native
DOM event object:
<input ng-keydown="$event.key === 'Enter' && submit()" />
Event policy can be declared once on the same element and applies to generated
event directives on that element:
<div
ng-click="$ctrl.activate($event)"
data-event-prevent
data-event-capture
></div>
Supported policy attributes:
| Attribute | Behavior |
|---|
data-event-prevent | Calls $event.preventDefault() first |
data-event-stop | Calls $event.stopPropagation() first |
data-event-capture | Registers the listener with capture: true |
data-event-once | Registers the listener with once: true |
data-event-passive | Registers the listener with passive: true |
data-event-passive cannot be combined with data-event-prevent, because
passive listeners cannot cancel default browser behavior.
ng-pointer-capture can be combined with an application directive that installs
native pointer listeners for game and board interactions:
<div ng-pointer-capture pointer-drag></div>
2 - Animation Directives and CSS Hooks
Use CSS class hooks and JavaScript animation factories with structural directives such as ng-if, ng-repeat, and ng-show.
AngularTS integrates animations into the same lifecycle that drives structural
directives. Add the animate attribute to an element and the $animate service
applies entry, exit, and class-change hooks at the appropriate DOM update.
How $animate integrates with directives
Structural directives such as ng-if, ng-repeat, ng-show, ng-hide,
ng-switch, and ng-include check for animation data before manipulating the
DOM. When animate is present, they delegate DOM operations to $animate:
| Operation | Without $animate | With $animate |
|---|
| Insert element | element.after(clone) | $animate.enter(clone, parent, after) |
| Remove element | element.remove() | $animate.leave(element) |
| Toggle class | element.classList.add(cls) | $animate.addClass(element, cls) |
| Swap classes | el.add(a); el.remove(b) | $animate.setClass(element, add, remove) |
This means you can add CSS transitions to any structural operation simply by
adding the animate attribute and writing the corresponding CSS rules.
CSS animation hook classes
When $animate performs an operation it applies a sequence of CSS classes in
two frames to give the browser time to set up the transition:
Element enter
ng-enter → ng-enter + ng-enter-active → (classes removed)
Element leave
ng-leave → ng-leave + ng-leave-active → element removed
Element move (ng-repeat reorder)
ng-move → ng-move + ng-move-active → (classes removed)
Class add/remove
ng-CLASS-add → ng-CLASS-add + ng-CLASS-add-active → CLASS applied
ng-CLASS-remove → ng-CLASS-remove + ng-CLASS-remove-active → CLASS removed
.card.ng-enter {
opacity: 0;
transform: translateY(-8px);
transition:
opacity 0.25s ease,
transform 0.25s ease;
}
.card.ng-enter-active {
opacity: 1;
transform: translateY(0);
}
/* Fade out when the element is removed */
.card.ng-leave {
opacity: 1;
transition: opacity 0.2s ease;
}
.card.ng-leave-active {
opacity: 0;
}
Animating ng-repeat lists
ng-repeat triggers ng-enter and ng-leave animations for items added to or
removed from the collection. Add the animate attribute on the repeated element
to opt in.
<ul>
<li class="task-item" ng-repeat="task in tasks" animate>
<span ng-bind="task.title"></span>
<button ng-click="removeTask(task)">Remove</button>
</li>
</ul>
animation: slideIn 0.25s ease forwards;
}
.task-item.ng-leave {
animation: slideOut 0.2s ease forwards;
}
.task-item.ng-move {
transition: all 0.3s ease;
}
@keyframes slideIn {
from { opacity: 0; transform: translateX(-16px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes slideOut {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(16px); }
}
.controller('TaskCtrl', ['$scope', function($scope) {
$scope.tasks = [
{ id: 1, title: 'Design wireframes' },
{ id: 2, title: 'Write tests' },
{ id: 3, title: 'Deploy to staging' }
];
$scope.removeTask = function(task) {
const idx = $scope.tasks.indexOf(task);
if (idx !== -1) $scope.tasks.splice(idx, 1);
};
}]);
Animating ng-show / ng-hide
ng-show and ng-hide both apply a temporary ng-hide-animate class alongside
ng-hide when the $animate service is active. This class serves as the
transition anchor:
<div animate>{{ message }}</div>
transition: opacity 0.3s ease, max-height 0.3s ease;
overflow: hidden;
}
/* State when hidden */
.notification.ng-hide {
opacity: 0;
max-height: 0;
}
/* Applied during the animation frame to enable the transition */
.notification.ng-hide-animate {
display: block !important;
}
JavaScript animations
Register JavaScript animation hooks with the module’s animation() method:
angular.getModule('app').animation('.flip-card', function () {
return {
enter: function (element, done) {
// Use Web Animations API or any library
element.animate(
[{ transform: 'rotateY(90deg)' }, { transform: 'rotateY(0deg)' }],
{ duration: 300, easing: 'ease-out' },
).onfinish = done;
return function (cancelled) {
if (cancelled) element.style.transform = '';
};
},
leave: function (element, done) {
element.animate(
[{ transform: 'rotateY(0deg)' }, { transform: 'rotateY(-90deg)' }],
{ duration: 250, easing: 'ease-in' },
).onfinish = done;
},
};
});
<div ng-repeat="card in cards" animate>{{ card.content }}</div>
Tip: JavaScript animations and CSS animations can coexist on the same
element. The $animate service runs CSS animations and JavaScript animation
hooks in parallel, calling done only after both complete.
Animation and the HTTP directives
The HTTP directives (ng-get, ng-post, etc.) also support the animate
attribute. When present, swapped content uses $animate.enter and
$animate.leave instead of direct DOM manipulation:
<div
ng-get="/api/posts"
trigger="load"
swap="innerHTML"
animate
class="post-content"
></div>
opacity: 0;
transition: opacity 0.4s ease;
}
.post-content.ng-enter-active {
opacity: 1;
}
3 - Data Binding Directives in AngularTS Explained
Explore ng-bind, ng-bind-html, ng-model, ng-class, ng-style, and ng-init with real examples covering one-way and two-way data binding.
Data binding directives synchronise values between the scope and the DOM without
requiring you to write event listeners or DOM queries by hand. AngularTS
provides one-way and two-way binding variants to cover every use case, from safe
text output to full form synchronisation.
ng-bind
ng-bind is the attribute equivalent of double-curly interpolation ({{ }}).
It watches the given scope expression and writes the result as the element’s
textContent. Because it sets textContent, it is immune to XSS — no HTML is
ever parsed.
<p>Hello, {{ user.name }}!</p>
<!-- Using ng-bind — element is empty until AngularTS compiles -->
<p>Hello, <span ng-bind="user.name"></span>!</p>
The implementation observes the expression’s reactive dependencies and updates
the text when one of them changes.
Tip: Prefer ng-bind over {{ }} in the <body> of server-rendered
pages to avoid the flash of uncompiled template (FOUC). The element starts
empty and is filled when Angular bootstraps.
Parameters
ng-bind
- Type:
expression - Required: yes
Any AngularTS expression. The result is converted to a string via stringify()
and written to element.textContent. null and undefined render as an empty
string.
ng-bind-template
ng-bind-template lets you embed multiple interpolated expressions inside a
single attribute value — useful when the surrounding text cannot hold a child
element.
<title ng-bind-template="{{pageTitle}} — {{siteName}}"></title>
<!-- Equivalent using child elements (not possible inside <title>) -->
The directive reacts to interpolation dependencies and writes the resulting
string to textContent.
ng-bind-template
- Type:
string with {{ }} expressions - Required: yes
A string literal containing one or more {{ expression }} placeholders. The
entire interpolated string is written to textContent.
ng-bind-html
ng-bind-html inserts the expression result directly into element.innerHTML.
Use this directive when you need to render server-provided or pre-sanitised
markup. It calls $parse during compilation to check for interpolation errors,
then watches the expression and sets innerHTML on every change.
<div ng-bind-html="article.body"></div>
.controller('ArticleCtrl', ['$scope', function($scope) {
$scope.article = {
body: '<p>Hello <strong>world</strong></p>'
};
}]);
Warning: ng-bind-html sets innerHTML directly. Always sanitise content
on the server before placing it in scope. Avoid interpolating raw user input
with this directive.
ng-bind-html
- Type:
expression - Required: yes
An expression evaluating to a string of HTML. The string is written to
element.innerHTML. null and undefined clear the element.
ng-model
ng-model establishes a two-way binding between a form input and a scope
property. Changes to the input update the scope; changes to the scope property
update the input. It is the backbone of AngularTS form handling.
Text input
<input type="text" ng-model="user.name" />
<p>Hello, {{ user.name }}!</p>
Checkbox
<input type="checkbox" ng-model="settings.notifications" />
<p ng-bind="settings.notifications ? 'On' : 'Off'"></p>
Select
<select ng-model="selected.country">
<option value="us">United States</option>
<option value="gb">United Kingdom</option>
</select>
<p>You selected: {{ selected.country }}</p>
Textarea
<textarea ng-model="message.body" rows="4"></textarea>
<p>Characters: {{ message.body.length }}</p>
ng-model creates an
NgModelController instance
that manages:
viewValue — the formatted value shown in the control (always a string
for native inputs)modelValue — the parsed value stored in the scopeparsers — pipeline from view to model (view → model transformation)formatters — pipeline from model to view (model → view transformation)validators — synchronous validator functions keyed by error nameasyncValidators — async validator functions that return Promiseserror — object whose keys are failing validator names
State properties
| Property | Type | Description |
|---|
pristine | boolean | true if the user has not interacted with this control |
dirty | boolean | true after the user has changed the value |
touched | boolean | true after the control has lost focus |
untouched | boolean | true before the control has ever been blurred |
valid | boolean | true if all validators pass |
invalid | boolean | true if any validator fails |
CSS classes
AngularTS automatically toggles CSS classes on the element:
.ng-valid {
border-color: green;
}
/* Applied when the model is invalid */
.ng-invalid {
border-color: red;
}
/* Applied when the user has not yet changed the value */
.ng-pristine {
}
/* Applied once the user has changed the value */
.ng-dirty {
}
/* Applied once the input has been blurred */
.ng-touched {
}
ng-model
- Type:
expression - Required: yes
An assignable AngularTS expression. The expression must be assignable (pointing
to a scope property), otherwise AngularTS throws an ngModel:nonassign error.
ng-class
ng-class conditionally adds and removes CSS classes based on a scope
expression. It supports three input formats: an object, an array, or a string.
Object syntax
Keys are class names; values are expressions. A class is applied when its value
is truthy.
<div ng-class="{ active: isActive, 'text-danger': hasError }">Status panel</div>
$scope.isActive = true;
$scope.hasError = false;
// Result: class="active"
For larger views, prefer projecting domain state into a view-model class map and
binding that map directly. This keeps templates readable and lets JavaScript
type checking validate the object shape.
<button ng-class="tile.classes">Fire</button>
/**
* @param {{ state: string, sunk: boolean }} tile
* @returns {ng.ClassMap}
*/
function tileClasses(tile) {
return {
placed: tile.state === 'unit',
hit: tile.state === 'hit',
miss: tile.state === 'miss',
sunk: tile.sunk,
};
}
$scope.tile = {
state: 'unit',
sunk: false,
classes: tileClasses({ state: 'unit', sunk: false }),
};
Array syntax
Each element is evaluated as a class name or object. Useful when combining
static and conditional classes.
<div ng-class="[baseClass, { highlighted: isSelected }]">Item</div>
$scope.baseClass = 'card';
$scope.isSelected = true;
// Result: class="card highlighted"
String syntax
The expression evaluates to a space-separated class string.
<div ng-class="currentTheme">Themed content</div>
$scope.currentTheme = 'theme-dark compact';
// Result: class="theme-dark compact"
The implementation uses reference counting internally (digestClassCounts) so
that when multiple ng-class directives compete on the same element, classes
are not prematurely removed while still in use.
Alternating repeated rows
Use the repeater’s $even and $odd locals in a normal ng-class map.
<ul>
<li
ng-repeat="item in items"
ng-class="{ 'row-even': $even, 'row-odd': $odd }"
>
{{ item.name }}
</li>
</ul>
ng-class
- String — a space-delimited list of class names.
- Object — keys are class names, values are truthy/falsy conditions.
- Array — each element is recursively processed using the above rules.
ng-style
ng-style watches a scope object and applies its key-value pairs as inline CSS
properties using element.style.setProperty. When the expression changes, the
old properties are first removed before the new ones are applied.
<div ng-style="boxStyles">Dynamic box</div>
'background-color': '#4f46e5',
'color': '#ffffff',
'padding': '16px',
'border-radius': '8px'
};
<p
ng-style="{ 'font-size': fontSize + 'px', 'font-weight': isBold ? 'bold' : 'normal' }"
>
Styled text
</p>
Note: CSS property names must use hyphen-case (background-color, not
backgroundColor) since the implementation calls element.style.setProperty
rather than assigning to element.style[key].
ng-style
- Type:
object - Required: yes
An expression evaluating to an object where keys are CSS property names in
hyphen-case and values are CSS value strings. Setting the expression to null
or undefined removes all previously applied inline styles.
ng-init
ng-init evaluates an expression during the pre-link phase — before child
directives are linked. It is most useful for initialising scope variables inline
without requiring a separate controller.
<div ng-init="count = 0; title = 'Hello'">
<button ng-click="count = count + 1">Clicked {{ count }} times</button>
</div>
<ul>
<li ng-repeat="item in items" ng-init="pos = $index + 1">
{{ pos }}. {{ item.name }}
</li>
</ul>
The implementation checks whether a controller is present on the element (via
getController) and, if so, evaluates the expression on the controller’s scope.
Otherwise it falls back to the current scope.
Warning: Use ng-init sparingly. For any non-trivial initialisation, use
a controller instead. Keeping logic in templates makes it harder to test and
maintain.
ng-init
- Type:
expression - Required: yes
An AngularTS expression or semicolon-separated list of expressions evaluated
once in the pre-link phase. The expression has access to the current scope.
4 - Form Directives and Validation in AngularTS
Complete guide to AngularTS form directives: ng-model, built-in validators, ng-messages, ng-model-options, and form state properties like valid and dirty.
AngularTS treats HTML forms as first-class citizens of the framework. Every
<form> element (and ng-form directive) creates a FormController instance
that tracks the aggregate validity and dirty state of all its inputs. Each input
bound with ng-model gets its own
NgModelController that
manages the view-to-model pipeline, validation, and CSS class hooks.
A plain <form> element is enhanced by AngularTS into a FormController. Give
the form a name attribute and the controller is published on the current scope
under that name, giving you programmatic access to validation state.
<form name="registrationForm">
<input type="email" name="email" ng-model="user.email" required />
<button type="submit" ng-disabled="registrationForm.invalid">Register</button>
</form>
.controller('RegistrationCtrl', ['$scope', function($scope) {
$scope.register = function() {
if ($scope.registrationForm.valid) {
// submit logic
}
};
}]);
| Property | Type | Description |
|---|
valid | boolean | true when all child controls are valid |
invalid | boolean | true when any child control is invalid |
pristine | boolean | true before any control has been changed |
dirty | boolean | true after any control has been changed |
submitted | boolean | true after the form’s submit event fires |
error | object | Keys are validator names; values are arrays of failing controls |
pending | object | Keys are validator names with pending async validators |
AngularTS automatically toggles these classes on both the <form> element and
each ng-model input:
| Class | Applied when |
|---|
ng-pristine | Control has not been changed |
ng-dirty | Control has been changed |
ng-valid | All validators pass |
ng-invalid | Any validator fails |
ng-submitted | Form has been submitted |
ng-touched | Input has been blurred at least once |
ng-untouched | Input has never been blurred |
ng-pending | An async validator is in progress |
input.ng-invalid.ng-dirty {
border: 2px solid #ef4444;
}
input.ng-valid.ng-dirty {
border: 2px solid #22c55e;
}
/* Show error messages only after the form is submitted or field is touched */
.field-error {
display: none;
}
input.ng-touched.ng-invalid ~ .field-error {
display: block;
}
ng-form creates a nested FormController that tracks its own controls
independently. Because browsers do not allow nested <form> elements, ng-form
is the standard way to group controls into sub-sections with their own validity
state.
<form name="outerForm">
<!-- Shipping address group -->
<ng-form name="shippingForm">
<input name="street" ng-model="shipping.street" required />
<input name="city" ng-model="shipping.city" required />
<p ng-if="shippingForm.invalid">Please complete shipping address.</p>
</ng-form>
<!-- Billing address group -->
<ng-form name="billingForm">
<input name="street" ng-model="billing.street" required />
<p ng-if="billingForm.invalid">Please complete billing address.</p>
</ng-form>
<button ng-disabled="outerForm.invalid">Submit</button>
</form>
The outer form’s valid is false if any nested ng-form is invalid, allowing
you to check a single top-level form while still presenting granular errors per
section.
All standard HTML input types are supported. For <input>, <textarea>, and
<select> elements, AngularTS registers type-specific parsers and validators
automatically when ng-model is present.
Text / Email / URL
<input
type="text"
name="username"
ng-model="user.username"
required
minlength="3"
maxlength="20"
ng-pattern="/^[a-z0-9_]+$/"
/>
<input type="email" name="email" ng-model="user.email" required />
<input type="url" name="website" ng-model="user.website" />
Number
<input
type="number"
name="age"
ng-model="user.age"
min="18"
max="120"
required
/>
Parses the input into a JavaScript number. Sets error.number if the value is
not numeric, error.min or error.max if out of range.
Checkbox
<!-- Simple boolean checkbox -->
<input type="checkbox" name="agree" ng-model="user.agreedToTerms" required />
Checkbox models use boolean values.
Radio
<label> <input type="radio" ng-model="plan" value="free" /> Free </label>
<label> <input type="radio" ng-model="plan" value="pro" /> Pro </label>
<label>
<input type="radio" ng-model="plan" value="enterprise" /> Enterprise
</label>
<p>Selected: {{ plan }}</p>
Select
<!-- Simple string options -->
<select name="country" ng-model="user.country" required>
<option value="">-- Choose a country --</option>
<option value="us">United States</option>
<option value="gb">United Kingdom</option>
</select>
<!-- Object options with ng-options -->
<select
ng-model="selectedRole"
ng-options="role.id as role.label for role in roles"
>
<option value="">-- Select a role --</option>
</select>
Built-in validators
required / ng-required
required makes the field mandatory. ng-required accepts an expression so you
can make a field conditionally required.
<!-- Conditionally required -->
<input
type="text"
ng-model="user.company"
ng-required="user.accountType === 'business'"
/>
The validator calls NgModelController.isEmpty on the view value. For text
inputs, empty means "". For checkboxes, empty means false.
minlength / ng-minlength
ng-model="user.password" ng-minlength="8" />
<p ng-if="form.password.error.minlength">
Password must be at least 8 characters.
</p>
maxlength / ng-maxlength
ng-model="tweet.text" ng-maxlength="280" />
<p>{{ 280 - tweet.text.length }} characters remaining</p>
pattern / ng-pattern
pattern accepts a regex literal (as an attribute value subject to
interpolation). ng-pattern accepts a scope expression that evaluates to a
RegExp object or a string.
<input type="text" ng-model="user.phone" pattern="^\d{10}$" />
<!-- Dynamic pattern from scope -->
<input
type="text"
ng-model="user.code"
ng-pattern="validationRules.codePattern"
/>
codePattern: /^[A-Z]{2}\d{4}$/
};
Note: Avoid the g (global) flag on patterns used with ng-pattern.
RegExp objects with the g flag maintain internal state between calls to
.test(), which causes alternating pass/fail results.
ng-messages
ng-messages simplifies displaying validation error messages. It watches a form
control’s error object and renders the first matching ng-message child (or
all matching, with the multiple attribute).
<form name="signupForm">
<div class="field">
<label>Email</label>
<input type="email" name="email" ng-model="user.email" required />
<div ng-messages="signupForm.email.error" role="alert">
<p ng-message="required">Email address is required.</p>
<p ng-message="email">Please enter a valid email address.</p>
</div>
</div>
</form>
By default, only the first matching error is shown. Add the multiple attribute
to show all failing validators at once:
<div ng-messages="signupForm.password.error">
<p ng-message="required">Password is required.</p>
<p ng-message="minlength">At least 8 characters required.</p>
<p ng-message="pattern">Must contain a number and special character.</p>
</div>
ng-message-default
ng-message-default acts as a fallback shown when none of the specific
ng-message keys match but there is at least one truthy error:
<div ng-messages="field.error">
<p ng-message="pattern">Invalid format.</p>
<p ng-message-default>This field has an error.</p>
</div>
Reusable message templates
Use ng-messages-include to load a shared message template file:
<div ng-messages="signupForm.email.error">
<div ng-messages-include="'/partials/common-messages.html'"></div>
<p ng-message="email">Not a valid email address.</p>
</div>
ng-model-options
ng-model-options controls when the model is updated and how updates are
debounced. It can be placed on a form (to apply to all controls) or on
individual inputs.
Debounce
Delay model updates by a given number of milliseconds after the user stops
typing:
<input
type="text"
ng-model="search.query"
ng-model-options="{ debounce: 300 }"
/>
This fires a search 300ms after the last keystroke rather than on every
character.
Update on blur
Only update the model when the input loses focus:
<input
type="text"
ng-model="user.username"
ng-model-options="{ updateOn: 'blur' }"
/>
Combined events
Update immediately on blur, but also debounced on default (which covers all
other events):
<input
type="text"
ng-model="user.slug"
ng-model-options="{
updateOn: 'blur default',
debounce: { 'default': 500, 'blur': 0 }
}"
/>
Available options
updateOn
Space-separated DOM event names that trigger model updates. Use "default" as a
placeholder for the control’s standard update event (e.g., "input" for text
inputs).
debounce
Milliseconds to wait before committing the view value. Can be an object mapping
event names to delays: { 'blur': 0, 'default': 500 }.
allowInvalid
When true, the model is updated even when the value is invalid (normally the
model is set to undefined when validation fails).
timezone
Timezone offset for date/time input parsing, e.g. "UTC" or "+0530".
The following example demonstrates a registration form with multiple input
types, validators, debouncing, and ng-messages error display.
<form name="regForm" ng-submit="register()">
<input name="email" type="email" ng-model="form.email" required />
<div ng-messages="regForm.email.error" ng-if="regForm.email.touched">
<p ng-message="required">Email is required.</p>
<p ng-message="email">Enter a valid email.</p>
</div>
<button ng-disabled="regForm.invalid">Create account</button>
</form>
.controller('RegistrationCtrl', ['$scope', function($scope) {
$scope.form = {};
$scope.submitRegistration = function() {
$scope.regForm.setSubmitted();
if ($scope.regForm.valid) {
// Call your API
console.log('Registering:', $scope.form);
}
};
}]);
5 - HTTP Directives: ng-get, ng-post, ng-put, ng-sse
Make HTTP requests and stream SSE from HTML using ng-get, ng-post, ng-put, ng-delete, and ng-sse — no JavaScript required for common data-fetching patterns.
AngularTS ships a family of declarative HTTP directives. Rather than wiring up
$http calls in a controller, you attach ng-get, ng-post, ng-put,
ng-delete, or ng-sse directly to HTML elements. The directives handle the
request lifecycle, DOM insertion, loading states, error handling, and explicit
response assignment — all configured through HTML attributes.
Similarity to HTMX
Developers familiar with HTMX may recognize a similar declarative, server-first
approach: requests can start from HTML, the server can return fragments, and an
element can declare where a response belongs. That similarity is a useful mental
model, not a compatibility or migration contract.
Learn each AngularTS pattern from its AngularTS contract. AngularTS combines
HTTP directives with scope state, bindings, components, and router states. For
example, an HTTP directive can prefetch JSON into scope while ng-click and
ng-if decide when to reveal it.
Do not infer AngularTS syntax or behavior from HTMX documentation. AngularTS
does not automatically implement HTMX attributes, extensions, events, request
headers, or history behavior. Use the attributes documented on this page and
AngularTS services when a pattern needs capabilities beyond them.
How they differ from $http
When you use $http directly you write controller code: define the request,
subscribe to the promise, update scope properties, handle errors, and trigger a
digest. The HTTP directives do all of this declaratively:
<button ng-click="loadUser()">Load user</button>
<p>{{ user.name }}</p>
$http.get('/api/user/1').then(function(res) {
$scope.user = res.data;
});
};
<button ng-get="/api/user/1" on-success="user = $res">Load user</button>
<p>{{ user.name }}</p>
JSON is available to on-success as $res; it never mutates scope implicitly.
HTML responses are compiled and inserted using the configured swap strategy.
ng-get
ng-get fires a GET request when the configured event occurs (default: click
for buttons, change for inputs, submit for forms).
<button ng-get="/api/weather?city=London" on-success="weather = $res">
Get weather
</button>
{{ weather.temperature }}°C — {{ weather.description }}
<button
ng-get="/partials/user-card.html"
data-swap="outerHTML"
data-target="#user-area"
>
Show profile
</button>
<div id="user-area"></div>
Automatic trigger
Use trigger="load" to fire the request immediately when the element is linked
(no user interaction required):
<div ng-get="/api/dashboard/stats" trigger="load" on-success="stats = $res">
<span ng-bind="stats.users"></span> users
</div>
Polling with interval
<div
ng-get="/api/live-count"
trigger="load"
on-success="status = $res"
interval="5000"
>
{{ count }} online
</div>
ng-post
ng-post fires a POST request. On <form> elements, the default trigger is
submit and the form data is collected via FormData. On buttons and other
elements, the trigger defaults to click.
<form ng-post="/api/contact" name="contactForm">
<input name="email" type="email" ng-model="contact.email" required />
<textarea name="message" ng-model="contact.message" required></textarea>
<button type="submit" ng-disabled="contactForm.invalid">Send</button>
</form>
<button
ng-post="/api/cart/add"
on-success="cartMessage = $res.message"
on-error="cartError = $res.error"
>
Add to cart
</button>
When the form element has an enctype attribute, the request body is
URL-encoded using Content-Type: application/x-www-form-urlencoded. Without
enctype, form data is sent as a JSON object.
ng-put
ng-put fires a PUT request. Use it to update resources:
<form
ng-put="/api/profile"
name="profileForm"
on-success="profileSaved = true"
data-state-success="dashboard"
>
<input name="name" ng-model="user.name" required />
<input name="email" type="email" ng-model="user.email" required />
<button type="submit">Save changes</button>
</form>
ng-delete
ng-delete fires a DELETE request. It shares all the same modifier attributes
as ng-get:
<li>
<span>{{ item.name }}</span>
<button
ng-delete="/api/items/{{ item.id }}"
data-swap="delete"
data-target="#item-{{ item.id }}"
>
Delete
</button>
</li>
ng-sse
ng-sse opens a persistent Server-Sent Events connection using the $sse
service. Incoming JSON is available to on-success as $res; HTML strings are
inserted using the configured swap strategy.
<div ng-sse="/api/events/notifications" swap="beforeend"></div>
<div ng-sse="/api/events/market" trigger="load" on-success="market = $res">
<p>{{ market.price | currency }}</p>
<p>{{ market.change }}%</p>
</div>
The connection is torn down automatically when the scope is destroyed (e.g.,
when navigating away). Reconnect behaviour and error logging are provided by the
$sse service.
app.get('/api/events/market', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ price: 42.5, change: 0.3 })}\n\n`);
}, 2000);
req.on('close', () => clearInterval(interval));
});
Shared modifier attributes
All HTTP directives accept the same set of modifier attributes to control their
behaviour:
swap
- Type:
string - Default:
innerHTML
Controls how the response HTML is inserted. Possible values:
innerHTML — replaces the element’s inner content (default)outerHTML — replaces the entire elementtextContent — inserts plain text without HTML parsingbeforebegin — inserts immediately before the elementafterbegin — inserts inside the element, before its first childbeforeend — inserts inside the element, after its last childafterend — inserts immediately after the elementdelete — removes the target element entirelynone — performs no DOM insertion
data-target
A querySelector selector for the element that receives the response. When
omitted, the directive element itself is the target.
<button ng-get="/api/user" data-target="#profile-card">Load</button>
<div id="profile-card"></div>
trigger
The DOM event that fires the request. Defaults to click for buttons and
generic elements, change for inputs/selects/textareas, and submit for forms.
Use "load" to trigger immediately on link.
latch
- Type:
interpolated expression
Re-fires the request every time the interpolated value changes.
<div ng-get="/api/search" latch="{{ query }}" swap="innerHTML">
{{ results.length }} results
</div>
interval
Fires the request immediately and then repeats every N milliseconds. The
interval is cleared when the scope is destroyed.
<div ng-get="/api/status" interval="10000">{{ status }}</div>
delay
Wait N milliseconds before sending the request after the trigger event fires.
throttle
Ignore later trigger events for N milliseconds after the request fires.
loading
When present, sets data-loading="true" on the element while the request is in
flight and data-loading="false" when it completes. Useful as a CSS hook.
<button ng-get="/api/data" loading>Load</button>
button[data-loading='true'] {
opacity: 0.6;
cursor: wait;
}
loading-class
A CSS class toggled on the element while the request is in flight.
<button ng-get="/api/data" loading-class="is-loading">Load</button>
on-success
Expression evaluated when the response has a 2xx status code. The response data
is available as $res.
<button ng-get="/api/items" on-success="items = $res">Fetch</button>
on-error
Expression evaluated when the response has a 4xx or 5xx status code. The
response data is available as $res.
<button
ng-post="/api/login"
on-success="redirect('/dashboard')"
on-error="loginError = $res.message"
>
Log in
</button>
data-state-success
Router state name to navigate to on success (calls $state.go).
data-state-error
Router state name to navigate to on error (calls $state.go).
animate
When present, enables $animate transitions for the swap operation. Requires
the $animate CSS hooks to be defined.
enctype
Sets the Content-Type request header and URL-encodes form data. Use
"application/x-www-form-urlencoded" to replicate a native HTML form
submission.
Practical examples
Loading a data table on mount
<table>
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Joined</th>
</tr>
</thead>
<tbody ng-get="/api/users" trigger="load" swap="innerHTML">
<!-- Populated with server-rendered rows -->
</tbody>
</table>
<ul id="post-list">
<li ng-repeat="post in posts">{{ post.title }}</li>
</ul>
<button
ng-get="/api/posts?page={{ nextPage }}"
ng-viewport
on-enter="loadMore()"
data-swap="beforeend"
data-target="#post-list"
>
Load more
</button>
Real-time notifications via SSE
<div class="notification-badge">
<span ng-bind="notifications.unread"></span>
</div>
<div
ng-sse="/api/events/notifications"
trigger="load"
on-success="notifications = $res"
></div>
<form
name="loginForm"
ng-post="/api/auth/login"
data-state-success="app.dashboard"
on-error="authError = $res.message"
>
<input type="email" name="email" ng-model="credentials.email" required />
<input
type="password"
name="password"
ng-model="credentials.password"
required
/>
<p ng-if="authError" ng-bind="authError"></p>
<button type="submit" ng-disabled="loginForm.invalid">Log in</button>
</form>
6 - Directive Overview
Learn how AngularTS directives attach behavior to HTML, how built-in directive groups are organized, and how to create custom directives.
Directives are how AngularTS attaches behavior and structure to HTML. A
directive is a marker on a DOM element or attribute that tells $compile to
attach behavior, transform DOM, wire events, create scopes, or connect
controllers.
Every built-in directive in AngularTS is applied as an HTML attribute using the
ng- prefix. The compiler normalizes prefixes, so ng-bind, data-ng-bind,
and x-ng-bind all match the same directive.
Exact custom directive contracts live in TypeDoc:
How Directives Are Matched
The restrict option controls where a directive can appear.
| Restrict | Match form | Example |
|---|
A | Attribute | <span ng-bind="name"></span> |
E | Element | <my-widget></my-widget> |
AE / EA | Attribute or element | <div ng-form> or <ng-form> |
Attribute directives are the common case in AngularTS. They keep the host
element in place and augment it.
Built-In Directive Groups
AngularTS groups its built-in directives by the user-facing job they perform.
Keep these groups in mind when choosing where to look in the docs.
| Group | Purpose | Examples |
|---|
| Data binding | Synchronize scope data with the view | ng-bind, ng-model, ng-class, ng-style |
| Structural | Add, remove, repeat, or switch DOM | ng-if, ng-repeat, ng-show, ng-hide, ng-switch |
| Forms | Track validity, dirty state, messages, and model options | form, ng-model, ng-messages, validators |
| HTTP | Trigger declarative network work from the DOM | ng-get, ng-post, ng-put, ng-delete, ng-sse |
| Animations | Coordinate directive-driven animation hooks | animate, $animate, CSS hooks |
| Advanced | Connect browser APIs and integrations | ng-worker, ng-wasm, ng-viewport, ng-pointer-capture |
Create A Custom Directive
Register directives on a module with .directive(name, factory). The factory
returns a directive definition object.
angular.createModule('demo', []).directive('highlight', () => {
return {
restrict: 'A',
scope: {
color: '@highlight',
},
link(scope, element) {
const paint = (color) => {
element.style.backgroundColor = color || 'yellow';
};
paint(scope.color);
scope.watch('color', paint);
},
};
});
<p highlight="gold">Pinned note</p>
Use compile() when the directive must transform template DOM before linking.
Use link() when it only needs to attach behavior to each compiled instance.
Execution Order
When multiple directives appear on the same element, AngularTS sorts them by
priority from highest to lowest. Directives with equal priority run in
registration order.
<li ng-repeat="item in items" ng-class="{ active: item.selected }">
{{ item.name }}
</li>
Structural directives such as ng-repeat and ng-if use high priorities and
terminal behavior because they replace or remove DOM before lower-priority
directives are linked.
Scope Choice
Use the default inherited scope for simple behavior. Create a child scope when
the directive needs local state. Use isolate scope bindings when the directive
is designed as a reusable widget with explicit inputs and callbacks.
scope: {
title: "@",
value: "=",
onSave: "&",
}
Prefer components for larger reusable UI pieces. Use directives for behaviors,
DOM integrations, structural transforms, and lightweight element coordination.
Next Steps
7 - Structural Directives: ng-if, ng-repeat, ng-switch
Master AngularTS structural directives including ng-if, ng-show, ng-hide, ng-repeat, ng-switch, ng-include, and ng-non-bindable.
Structural directives reshape the DOM by adding, removing, or repeating
elements. Unlike attribute directives that modify an existing element,
structural directives use transclusion to stamp out or remove entire sections of
the template. They run at high priority (600–1000) and set terminal: true so
that lower-priority directives do not compile until the structure is resolved.
ng-if
ng-if conditionally includes or removes a DOM element based on a scope
expression. When the expression becomes falsy, the element and its entire
subtree — including child scopes and event listeners — are destroyed. When it
becomes truthy again, a fresh element and child scope are created.
<div ng-if="user.role === 'admin'">
<h2>Admin Panel</h2>
<p>Welcome, {{ user.name }}. You have full access.</p>
</div>
<div ng-if="isLoggedIn">
<p>Welcome back, {{ user.name }}!</p>
<button ng-click="logout()">Log out</button>
</div>
<div ng-if="!isLoggedIn">
<p>Please <a href="/login">sign in</a> to continue.</p>
</div>
The implementation uses transclude: "element" at priority 600, which means the
compiler replaces the element with a comment placeholder and hands the element
template to the transclusion function. When the expression turns truthy, the
transclusion function clones the template and inserts it after the comment. When
it turns falsy, the child scope is destroyed and the clone is removed.
If the $animate service is available on the element, ng-if delegates to
$animate.enter and $animate.leave to trigger CSS transition hooks.
Note: ng-if vs ng-show: ng-if completely removes the element
from the DOM (destroying the child scope), while ng-show keeps the element
in the DOM and toggles an ng-hide CSS class. Use ng-if when the hidden
content is expensive to keep around or when it should not run watchers while
invisible.
Parameters
ng-if
- Type:
expression - Required: yes
An expression evaluated on each digest. When truthy, the element is inserted
into the DOM in a new child scope. When falsy, the element and its child scope
are destroyed.
ng-show / ng-hide
ng-show and ng-hide toggle element visibility without removing the element
from the DOM. They work by adding or removing the ng-hide CSS class, which
sets display: none.
ng-show
Removes ng-hide when the expression is truthy, showing the element.
<div ng-show="form.submitted">
<p>Thank you! Your form was submitted successfully.</p>
</div>
ng-hide
Adds ng-hide when the expression is truthy, hiding the element.
<div ng-hide="isLoading">
<p>Content is ready.</p>
</div>
<div ng-show="isLoading">
<p>Loading...</p>
</div>
Both directives integrate with $animate. When the animate service detects the
element has animation hooks, they call $animate.addClass or
$animate.removeClass with the temporary class ng-hide-animate for the
duration of the animation.
.my-panel.ng-hide {
opacity: 0;
}
.my-panel.ng-hide-animate {
transition: opacity 0.3s ease;
}
ng-show
- Type:
expression - Required: yes
When truthy, ng-hide class is removed from the element, making it visible.
ng-hide
- Type:
expression - Required: yes
When truthy, ng-hide class is added to the element, hiding it.
ng-repeat
ng-repeat iterates over a collection (array or object) and stamps a copy of
the template for each item. Each copy gets its own child scope populated with
the iteration variables below.
Special scope properties
| Variable | Type | Description |
|---|
$index | number | Zero-based index of the current iteration |
$first | boolean | true for the first item |
$last | boolean | true for the last item |
$middle | boolean | true when neither first nor last |
$even | boolean | true when $index is even |
$odd | boolean | true when $index is odd |
Repeating over an array
<ul>
<li ng-repeat="product in products">
<strong>{{ product.name }}</strong> — ${{ product.price }}
<span ng-if="$first">(newest)</span>
<span ng-if="$last">(oldest)</span>
</li>
</ul>
Repeating over an object
Use the (key, value) tuple syntax to iterate over an object’s own enumerable
properties. Keys starting with $ are excluded automatically.
<dl>
<div ng-repeat="(key, value) in user">
<dt>{{ key }}</dt>
<dd>{{ value }}</dd>
</div>
</dl>
Alias with as
The as clause aliases the filtered collection to a new scope variable. This is
useful when you apply filters to the collection and need the filtered count.
<p>{{ filtered.length }} of {{ products.length }} items</p>
<ul>
<li ng-repeat="product in products | filter:searchText as filtered">
{{ product.name }}
</li>
</ul>
Animation support
Add the animate attribute to enable $animate.enter / $animate.leave on
items:
<li ng-repeat="item in items">{{ item.name }}</li>
opacity: 0;
transition: opacity 0.3s;
}
.list-item.ng-enter-active {
opacity: 1;
}
.list-item.ng-leave {
opacity: 1;
transition: opacity 0.3s;
}
.list-item.ng-leave-active {
opacity: 0;
}
ng-repeat
- Type:
string - Required: yes
Expression in one of the forms:
item in collection(key, value) in objectitem in collection | filter as alias
ng-switch
ng-switch renders exactly one child block matching the current value of a
watched expression. It is the structural equivalent of a JavaScript switch
statement.
<div ng-switch="user.status">
<div ng-switch-when="active">
<p>Account is active. Welcome, {{ user.name }}!</p>
</div>
<div ng-switch-when="suspended">
<p>Your account has been suspended. Please contact support.</p>
</div>
<div ng-switch-when="pending">
<p>Your account is awaiting verification.</p>
</div>
<div ng-switch-default>
<p>Unknown account status.</p>
</div>
</div>
ng-switch-when registers its transclusion function under the key !value (to
avoid collisions with $-prefixed keys) using an internal NgSwitchController.
When the watched expression changes, the currently shown block has its scope
destroyed (with an optional $animate.leave) and the matching block is
transcluded into place.
Multiple values on one case
The ng-switch-when-separator attribute allows a single ng-switch-when to
match multiple values:
<div ng-switch="day">
<div ng-switch-when="Saturday Sunday" ng-switch-when-separator=" ">
Weekend!
</div>
<div ng-switch-default>Weekday</div>
</div>
ng-switch
- Type:
expression - Required: yes
The expression whose value is compared against ng-switch-when values.
ng-switch-when
- Type:
string - Required: yes
The literal string value to match against the ng-switch expression.
ng-switch-default
Rendered when no ng-switch-when matches the current value.
ng-include
ng-include fetches an external HTML template, compiles it in the current scope
(or a new child scope), and inserts it into the DOM. It watches the URL
expression and replaces the content whenever the URL changes.
<div ng-include="'/partials/user-profile.html'"></div>
<!-- Include a dynamic template based on user role -->
<div ng-include="'/partials/nav-' + user.role + '.html'"></div>
The directive emits three events on the scope:
$includeContentRequested — when the template request begins$includeContentLoaded — when the template is compiled and inserted$includeContentError — when the template request fails
<div
ng-include="templateUrl"
ng-init="templateUrl = '/partials/home.html'"
onload="onTemplateLoaded()"
></div>
console.log('Template inserted successfully');
};
ng-include
- Type:
expression - Required: yes
Expression evaluating to the URL of the template to load. The URL is fetched via
$templateRequest (which uses the template cache if available).
onload
Expression evaluated after the template is compiled and inserted.
When truthy, calls $anchorScroll after the template is inserted.
ng-non-bindable
ng-non-bindable tells the AngularTS compiler to skip the element and all its
descendants entirely. No interpolation, directives, or watches are set up inside
the marked section.
<pre ng-non-bindable>
<p>Use {{ expression }} to interpolate values.</p>
<div ng-bind="myValue"></div>
</pre>
<div ng-non-bindable>{% raw %}{{ jinja_template_variable }}{% endraw %}</div>
Note: ng-non-bindable is essential when displaying code documentation,
Jinja/Twig snippets, or any content that uses {{ }} but should not be
treated as AngularTS expressions.