This section is a work in progress. Its content will be updated regularly but
feel free to rely on AngularJS documentation
in the meantime.
What is AngularTS?
AngularTS is buildless, type-safe and reactive JS framework for building
stuctured web applications at any scale. It continues the legacy of
AngularJS by providing the best developer experience
via immediate productivity without the burden of JS ecosystem tooling. Getting
started with AngularTS does not even require JavaScript. All you need is a
little bit of HTML. Below is a canonical example of a counter:
Example
<sectionng-appng-cloak><buttonclass="btn btn-dark"ng-init="count = 0"ng-click="count++"> Count is: {{ count }}
</button></section>
Result
This code demonstrates the following key AngularTS features:
HTML-first: AngularTS is designed for HTML-first approach, meaning your
application logic can be expressed declaratively in your markup using custom
attributes–called directives. Here, we are using ng-init directive to
initialize our application state and ng-click directive to add an event
handler that changes our state.
Template-driven: AngularTS’s built-in template engine automatically keeps
the UI in sync with your application state, eliminating the need for manual
DOM tracking and updates. The {{count}} expression above is an example of
Angular’s interpolation syntax. As the value of count variable increases,
our UI is updated with the new state.
Island-first and zero-cost: AngularTS creates an application on any HTML
tag with ng-app attribute, allowing multiple independent applications
(modules) to live on a single page. This allows AngularTS to work alongside
your existing tech stack where the majority of your page is rendered on the
server, while AngularTS is isolated to small “islands” (regions of your page)
where custom interactivity or personalization is required.
Micro-framework appearance: With its minimal setup, AngularTS is
well-suited for quick experiments, LLM-generated code, and learning web
development in general. But beneath its lightweight surface, it supports
structured enterprise design patterns, MVC architecture, and component-driven
design. With its rich directive library, state-based routing and support for
animations, AngularTS is a complete package for building large SPAs, server,
mobile, and desktop applications.
1 - Get Started
1.1 - AngularTS: modern evolution of AngularJS
AngularTS preserves AngularJS’s HTML-first model and dependency injection while adding reactive change detection, TypeScript support, and native browser APIs.
AngularTS is a modernized continuation of AngularJS — carrying forward its three core pillars (string interpolation, dependency injection, and two-way data binding) while rebuilding the internals around a reactive change-detection model, full TypeScript support, and direct access to native browser APIs. It requires no build step and no bundler to get started.
What AngularTS preserves from AngularJS
AngularJS was the result of a decade of engineering by the Angular team at Google and accumulated one of the largest test suites in open-source JavaScript. AngularTS inherits that foundation directly:
Declarative HTML templates using familiar ng-* directives
Dependency injection container for organizing and composing application services
Two-way data binding between the DOM and application state
Controllers, filters, and the module system — all structurally compatible with AngularJS patterns
If you have existing AngularJS knowledge, the mental model transfers directly.
What AngularTS adds
AngularTS extends the AngularJS foundation with modern primitives and new capabilities:
Reactive change detection
Proxy-based reactivity replaces the digest cycle. The DOM updates only when data actually changes — no polling, no virtual DOM diffing.
Native DOM and Promises
Directives and controllers work directly with native DOM APIs. The $q and $timeout abstractions are replaced by native Promise and setTimeout.
Built-in enterprise router
ng-router is a port of ui-router, supporting nested views, state transitions, resolves, and URL matching out of the box.
HTMX-inspired HTTP directives
ng-get, ng-post, ng-put, and ng-delete let you make HTTP requests declaratively from HTML attributes.
Real-time injectables
$websocket, $sse (Server-Sent Events), $rest, Web Workers, and WebAssembly modules are first-class injectable services.
Built-in animations
CSS and JavaScript animation support ships in the core package with no additional dependencies.
When to use AngularTS
AngularTS is a strong fit for these scenarios:
Server-rendered applications with interactive islands. Any HTML element can host an independent ng-app. You can drop AngularTS into a server-rendered page and add interactivity to specific regions without restructuring the whole application.
Applications where a build step is a liability. AngularTS loads from a CDN script tag and runs directly in the browser. There are no compilation steps, no bundler configuration files, and no Node.js required to develop or deploy.
Large-scale SPAs that need structure. The module system, dependency injection, state-based router, and MVC architecture scale to enterprise applications. AngularTS is not just a micro-library — it is a complete framework for applications of any size.
Migrating from AngularJS. If you maintain an AngularJS codebase and want to modernize incrementally, AngularTS preserves the API surface you already know.
How it compares to other frameworks
AngularTS
React
Vue
Angular (v2+)
Build step required
No
Yes
Optional
Yes
CDN drop-in
Yes
Partial
Yes
No
Two-way binding
Yes
No
Yes
Yes
Dependency injection
Yes
No
No
Yes
HTML-first templates
Yes
No (JSX)
Yes
Yes
Bundle size
Small (UMD)
Medium
Small
Large
Note: Angular 2+ (also called just “Angular”) is a complete rewrite of AngularJS and shares no API surface with it. AngularTS is a continuation of AngularJS — not a migration target from Angular 2+.
Philosophy
AngularTS stays as close to web standards as possible. It avoids inventing abstractions where the platform already provides them: native Promise instead of $q, native fetch under the hood for $http, direct DOM element references in directives instead of jQuery wrappers. This keeps the mental model small and the debugging experience familiar.
The result is described by the project as “a high-performance, buildless, multi-paradigm and battle-tested JS framework.”
Add AngularTS via a CDN script tag or npm. The package ships TypeScript declarations and supports auto-bootstrap with ng-app or manual bootstrap.
AngularTS can be added to any project in two ways: a single <script> tag for zero-configuration browser use, or an npm package for projects that use a bundler or want TypeScript declarations. Both approaches support the full framework — there is no difference in available features between the two.
CDN
The fastest way to get started is to load AngularTS directly from jsDelivr. No installation, no configuration — just add the script to your HTML file:
<html><head><scriptsrc="https://cdn.jsdelivr.net/npm/@angular-wave/angular.ts/dist/angular-ts.umd.min.js"></script></head><body><divng-appng-init="x = 'world'"> Hello {{ x }}
</div></body></html>
The UMD build exposes the angular global on window and auto-bootstraps any element with an ng-app attribute once the DOM is ready.
Tip: The CDN URL always points to the latest published version on npm. To pin a specific version, include it in the URL: https://cdn.jsdelivr.net/npm/@angular-wave/angular.ts@0.26.0/dist/angular-ts.umd.min.js
npm
Install the package from the npm registry:
npm install @angular-wave/angular.ts
yarn add @angular-wave/angular.ts
pnpm add @angular-wave/angular.ts
The package ships two distribution formats:
ESM (dist/angular-ts.esm.js) — the default entry point for bundlers
UMD (dist/angular-ts.umd.js) — for direct browser use
Import the library in your entry file:
When loaded in a browser environment, the angular singleton is also assigned to window.angular automatically.
TypeScript setup
The published package includes generated TypeScript declarations under @types/. No separate @types/ package is required.
After installing, TypeScript will resolve types automatically. You can reference the type namespace in your project:
Info: The ng namespace provides types for scopes, injectors, services, directives, and all other AngularTS primitives. It is declared globally by the package and available anywhere TypeScript resolves the package types.
Auto-bootstrap with ng-app
The simplest way to start an AngularTS application is the ng-app attribute. Place it on any HTML element and AngularTS will bootstrap that element as the application root when the DOM is ready:
<divng-app> {{ 1 + 1 }}
</div>
To connect a named module, set ng-app to the module name:
<divng-app="myApp"><png-controller="GreetController">{{ greeting }}</p></div><scriptsrc="https://cdn.jsdelivr.net/npm/@angular-wave/angular.ts/dist/angular-ts.umd.min.js"></script><script>angular.module("myApp",[]).controller("GreetController",function($scope){$scope.greeting="Hello from AngularTS";});</script>
Multiple independent ng-app elements can exist on the same page. Each becomes its own isolated application instance.
Strict dependency injection
Add the strict-di attribute alongside ng-app to enable strict mode, which requires explicit dependency annotations and rejects minified code that relies on function parameter names:
...
</div>
Manual bootstrap with angular.bootstrap()
For full control over when and how your application starts, call angular.bootstrap() directly instead of using ng-app:
Optional configuration; defaults to { strictDi: false }
It returns the $injector instance for the bootstrapped application.
Warning: Do not call angular.bootstrap() on an element that already has an ng-app attribute, or on an element that contains ng-view, ng-if, or other transclusion directives. This causes the root element and injector to be misplaced.
Learn how the AngularTS module system organizes your application.
1.3 - Build your first AngularTS app
A step-by-step guide to creating modules, controllers, and directives in AngularTS — with a counter example and a complete todo list application.
AngularTS apps are built from HTML and JavaScript — no compilation required. This guide walks through creating a module, wiring up a controller, and using directives to bind data to the DOM. By the end you will have a working counter and a functional todo list.
Add AngularTS to your page
Create an HTML file and include the AngularTS script from the CDN. This single tag is all you need to get the full framework:
<!doctype html><html><head><metacharset="UTF-8"/><title>My AngularTS App</title><scriptsrc="https://cdn.jsdelivr.net/npm/@angular-wave/angular.ts/dist/angular-ts.umd.min.js"></script></head><body><!-- application markup goes here --></body></html>
If you are using npm, install the package and import the singleton instead:
npm install @angular-wave/angular.ts
import{angular}from"@angular-wave/angular.ts";
Create a module
A module is the top-level container for your application. It holds controllers, services, directives, and filters. Create one by calling angular.module() with a name and an empty dependency array:
constapp=angular.module("myApp",[]);
The first argument is the module name. The second argument lists other modules your module depends on — an empty array means no dependencies. You reference this name in the ng-app attribute to tell AngularTS which module to bootstrap.
Connect the module to your HTML by adding ng-app to a container element:
<bodyng-app="myApp"><!-- AngularTS controls everything inside this element --></body>
Add a controller
Controllers attach behavior to a region of the DOM. They receive a $scope object — a plain JavaScript object that acts as the data model for their template. Anything you put on $scope becomes available in the HTML template.
The {{ count }} expression is AngularTS’s interpolation syntax — it renders the current value of $scope.count and updates automatically whenever the value changes. ng-click binds a click event to the controller method.
Use directives in your template
Directives are the building blocks of AngularTS templates. They extend HTML with behavior declared as attributes or element names. The core library ships over 50 directives covering data binding, conditional rendering, list rendering, forms, and HTTP requests.
Here is a complete counter example using only HTML attributes and no separate JavaScript file:
<!doctype html><html><head><scriptsrc="https://cdn.jsdelivr.net/npm/@angular-wave/angular.ts/dist/angular-ts.umd.min.js"></script></head><body><sectionng-appng-cloak><buttonng-init="count = 0"ng-click="count++"> Count is: {{ count }}
</button></section></body></html>
Key directives used here:
ng-app — designates the root element of the application and triggers auto-bootstrap
ng-cloak — hides the element until AngularTS has compiled the template, preventing a flash of unrendered {{ }} expressions
ng-init — initializes a scope variable inline; useful for simple cases without a controller
ng-click — evaluates an expression when the element is clicked
Complete example: todo list
The following example demonstrates a more complete application using a named module, a controller, two-way binding with ng-model, list rendering with ng-repeat, and conditional display with ng-show. Everything runs from a single HTML file.
<html><head><metacharset="UTF-8"/><title>Todo List</title><scriptsrc="https://cdn.jsdelivr.net/npm/@angular-wave/angular.ts/dist/angular-ts.umd.min.js"></script><style>.done{text-decoration:line-through;color:#999;}</style></head><bodyng-app="todoApp"><divng-controller="TodoController"><h1>Todo List</h1><!-- Add new item --><formng-submit="addTodo()"><inputng-model="newTodo"placeholder="What needs doing?"required/><buttontype="submit">Add</button></form><!-- Remaining count --><png-show="todos.length > 0"> {{ remaining() }} of {{ todos.length }} remaining
</p><!-- List of todos --><ul><ling-repeat="todo in todos"><inputtype="checkbox"ng-model="todo.done"/><spanng-class="{ done: todo.done }">{{ todo.text }}</span><buttonng-click="removeTodo($index)">Remove</button></li></ul><!-- Clear completed --><buttonng-click="clearDone()"ng-show="todos.length > remaining()"> Clear completed
</button></div><script>angular.module("todoApp",[]).controller("TodoController",function($scope){$scope.todos=[{text:"Learn AngularTS",done:true},{text:"Build something",done:false},];$scope.newTodo="";$scope.addTodo=function(){if($scope.newTodo.trim()){$scope.todos.push({text:$scope.newTodo.trim(),done:false});$scope.newTodo="";}};$scope.removeTodo=function(index){$scope.todos.splice(index,1);};$scope.remaining=function(){return$scope.todos.filter(function(t){return!t.done;}).length;};$scope.clearDone=function(){$scope.todos=$scope.todos.filter(function(t){return!t.done;});};});</script></body></html>
This example uses:
Directive
Purpose
ng-model
Two-way binding between the input value and $scope.newTodo
ng-submit
Calls addTodo() when the form is submitted
ng-repeat
Renders a <li> for each item in $scope.todos
ng-class
Adds the done CSS class when todo.done is true
ng-show
Shows the element only when the expression is truthy
ng-click
Calls a scope function when the element is clicked
Using TypeScript
If you are working with npm and TypeScript, annotate the controller function using the ng.Scope type:
Use built-in services for HTTP, WebSockets, REST, and more.
2 - Core Concepts
2.1 - Angular Runtime
Use the Angular runtime to create modules, bootstrap applications, access injectors, and bridge external code.
Angular is the runtime entry point for AngularTS. It owns module registration,
application bootstrap, injector creation, cached DOM helpers, and the
event-based invocation helpers exposed through window.angular.
The built-in ng module is prepended automatically. Use strictDi when code
must be safe for minification.
Each element can host only one application. Bootstrapping an element that
already has an injector throws ng:btstrpd.
Auto-Bootstrap
angular.init() scans an element or document for ng-app roots. The first root
uses the current Angular instance. Additional roots are bootstrapped as
sub-applications and stored in angular.subapps.
You usually do not need to call this yourself for static pages because AngularTS
runs auto-bootstrap when the script loads. Call it manually when dynamically
adding new ng-app roots.
Create A Standalone Injector
Use angular.injector() when tests or non-DOM code need services without
compiling an application root.
Use defineAngularElement() from @angular-wave/angular.ts/runtime/web-component
when an AngularTS feature should ship as a native web component. The helper
creates a custom runtime, registers only the directives and services you list,
defines the custom element, and builds the injector without requiring a host
page bootstrap.
Use these helpers for small integration boundaries such as browser callbacks,
legacy scripts, or embedded widgets. Normal application code should prefer
dependency injection.
Locate Named Scopes
getScopeByName() searches from $rootScope for a scope with a matching
$scopename.
2.2 - Reactive change detection with ES6 Proxy scopes
See how AngularTS replaces the AngularJS digest loop with ES6 Proxy interception, scheduling microtask DOM updates that only re-evaluate affected bindings.
Change detection is how a framework decides when to update the DOM to reflect new data. AngularJS used a polling mechanism called the digest cycle — every time something might have changed, AngularJS ran all registered watchers, compared old and new values, and repeated until nothing changed. AngularTS replaces this entirely with ES6 Proxy-based reactive observation: the framework knows exactly which property changed, which bindings depend on it, and schedules only those bindings to re-evaluate.
The digest cycle problem
In AngularJS, every $watch registered anywhere in the application was checked on every digest. A large application could have thousands of watchers running on every user interaction, mouse move, or HTTP response. This was O(n) in the number of watchers per cycle, and cycles could chain into one another.
AngularTS eliminates this entirely. There are no cycles. There is no polling.
How Proxy-based reactivity works
When AngularTS creates a scope via createScope(), it wraps the plain object in a Proxy whose handler is a Scope instance. The Scope class implements the set trap:
O(1) lookup: Listeners are stored in a Map<string, Listener[]> keyed by property name. When count changes, only listeners registered under 'count' are scheduled — not every watcher in the application.
Microtask scheduling: _scheduleListener calls queueMicrotask(), which defers the flush until after the current synchronous call stack completes. Multiple changes to the same property in the same tick are coalesced.
Recursive proxying: When you assign an object — $scope.user = { name: 'Alice' } — the new value is itself wrapped in a Proxy. Nested property changes ($scope.user.name = 'Bob') are tracked just as well as top-level ones.
A concrete example
$scope.count=0;$scope.increment=function(){$scope.count+=1;// At this point the Proxy set trap fires:
// 1. Stores the new value
// 2. Looks up listeners for 'count' in the watchers Map
// 3. Schedules them via queueMicrotask
// 4. Returns — no $apply() needed
};}]);
<buttonng-click="increment()">+</button><span>{{ count }}</span><!-- binding re-evaluates only when 'count' changes --></div>
When increment() fires, the Proxy intercepts the assignment to count, finds the binding registered for 'count', and schedules it. The DOM update happens on the next microtask — after increment() returns but before the browser renders the next frame.
Comparison with AngularJS
AngularJS (1.x)
AngularTS
Detection mechanism
Dirty-checking digest loop
ES6 Proxy set trap
Watcher lookup cost
O(n) — all watchers checked
O(1) — direct Map lookup by property name
Trigger
Manual digest entry required for async code
Automatic — Proxy intercepts every assignment
Update granularity
All watchers, all the time
Only bindings for the changed property
Nested objects
Shallow by default; $watchCollection needed for deep
Deep — nested objects are automatically proxied
Async code
Must manually enter change detection
No wrapping needed for standard async (Promise, fetch, etc.)
When no $apply is needed
Because the Proxy fires synchronously on every assignment, any code that assigns to a scope property — whether inside a controller, a service callback, or a Promise handler — automatically triggers the right DOM update:
$scope.users=[];$scope.loading=true;// No $apply() needed — the Proxy intercepts the assignment
$http.get('/api/users').then(({data})=>{$scope.users=data;// triggers DOM update for {{ users }}
$scope.loading=false;// triggers DOM update for ng-if="loading"
});}]);
Tip: If you are integrating a third-party library that updates data outside of AngularTS (such as a raw WebSocket callback or a non-Promise-based timer), and the library stores results in scope properties, those assignments still flow through the Proxy and trigger updates automatically. No $apply wrapper is needed.
Microtask batching
Multiple property changes within the same synchronous block are batched. The listener scheduler enqueues a queueMicrotask flush only once per tick:
_enqueueScheduledTask(task: ScheduledTask):void{constscheduler=this._listenerScheduler;scheduler._queue.push(task);if(!scheduler._queued&&!scheduler._flushing){scheduler._queued=true;queueMicrotask(()=>{this._flushScheduledTasks();// runs all queued listener notifications at once
});}}
If you set ten properties in one synchronous function, all ten listener notifications are flushed together in a single microtask. The DOM is updated once, not ten times.
Post-render layout work
Use $afterRender when a controller needs to read layout after AngularTS has applied the DOM work from the current flush:
AngularTS coalesces $afterRender to one callback per controller instance per render flush. The hook runs after directive and binding DOM mutations have completed, after linked children from structural directives such as ng-repeat exist, after class/style/attribute bindings for that flush are applied, and after one browser animation frame gives layout a chance to settle. It does not wait for external resources such as fonts or images by default.
For explicit scheduling outside the controller lifecycle, import afterRender or queueAfterRender:
Objects that carry $nonscope: true on the instance or constructor.
This prevents the framework from wrapping DOM nodes or native collections in Proxies, which would be incorrect and slow.
// Prevents this class from being wrapped in a Proxy
static$nonscope=true;readonlyapiBase='https://api.example.com';}// Or per-instance:
$scope.rawData=Object.assign(newSomeClass(),{$nonscope: true});
When to use $watch
In the reactive proxy model, $watch is rarely necessary for keeping the DOM in sync — that happens automatically. Use $watch when you need to run side-effect code in response to a scope property changing:
$scope.$watch('selectedTab',function(newTab){externalTabWidget.activate(newTab);});// Trigger a service call when a search term changes
$scope.$watch('searchQuery',function(query){if(query&&query.length>2){searchService.find(query).then(results=>{$scope.results=results;});}});// React to a computed condition
$scope.$watch('items.length > 100',function(tooMany){$scope.showPagination=tooMany;});
Note:$watch on a constant expression — a bare string literal, number, or boolean — is evaluated exactly once and the returned deregistration function is a no-op. The runtime detects the _constant flag on the compiled expression and avoids registering a watcher at all.
Watcher count and $$watchersCount
You can inspect how many active watchers are registered in a scope subtree:
console.log($scope.$$watchersCount);
This is computed by walking the _watchers Map and counting entries whose _scopeId matches any scope in the subtree. It is useful for identifying scopes with unexpectedly high watcher counts during performance profiling.
Performance characteristics
Only affected bindings update
A change to user.name schedules only the bindings that depend on name. Thousands of unrelated bindings are never touched.
No re-entrancy problems
The scheduler tracks a _flushing flag. If a listener notification causes another property change, that change is enqueued and flushed in a follow-up microtask rather than re-entrantly.
Deep tracking at zero cost
Nested objects are proxied at assignment time, not at watch time. There is no `` or explicit deep-watch flag — all depths are tracked uniformly.
Scope destruction cleans up
When $destroy() is called, all watcher entries for that scope’s $id are removed from the shared _watchers Map in a single O(n) pass, with O(1) swap-pop removal for each matched entry.
2.3 - Dependency injection and the AngularTS injector
Understand how the AngularTS injector resolves named tokens, how to annotate dependencies, and how the provider pattern controls the config and run phases.
Dependency injection (DI) is the mechanism AngularTS uses to supply components with the services they need. Rather than constructing dependencies directly, you declare what you need by name and the injector finds, instantiates, and delivers each dependency. This keeps components decoupled, composable, and straightforward to test in isolation.
How the injector works
When you call angular.bootstrap() (or use the ng-app directive), AngularTS calls createInjector() with your list of modules. The injector builds two internal caches:
Provider cache — holds provider objects, accessible during the config phase.
Instance cache — holds fully constructed service singletons, built on first request.
When a service is requested via $injector.get('myService'), the injector looks up myServiceProvider, calls its $get method (injecting that method’s own dependencies), caches the result, and returns it. Every subsequent get returns the same instance.
// Retrieve a service
const$http=injector.get('$http');// Check existence without throwing
if(injector.has('myOptionalService')){constsvc=injector.get('myOptionalService');}// Invoke a function with injection
injector.invoke(['$rootScope','$http',function($rootScope,$http){// both dependencies are injected automatically
}]);
Declaring dependencies
AngularTS reads dependency names from the function’s arguments — but argument names are erased by minifiers. The safe, minification-proof approach is array annotation: an array where every element except the last is a dependency name string, and the last element is the function.
Note: The $inject static property on a class is the TypeScript-idiomatic form of array annotation. When present, AngularTS reads it in preference to inspecting function argument names.
Strict DI mode
Passing { strictDi: true } to angular.bootstrap() (or adding the strict-di attribute to the ng-app element) disables implicit annotation. Every injectable must carry explicit annotations. This catches minification bugs at development time.
<divng-app="myApp"strict-di></div>
Under strict DI, any function that reaches the injector without annotations throws immediately — even if the un-annotated function would have worked in development.
Injectable types
value
A fixed JavaScript value. Registered with $provide.value(). Not available during the config phase.
constant
Like value, but available during the config phase and cannot be overridden by a decorator.
factory
A function whose return value becomes the singleton. Must not return undefined.
service
A constructor function. Instantiated with new once; the instance is the singleton.
provider
The most flexible type. An object with a $get method. Can expose configuration methods accessible during the config phase.
decorator
Wraps an existing service. Receives $delegate (the original) and returns a replacement or augmented version.
The provider pattern
Providers give you a way to configure a service before any instance is created. During the config phase the provider itself is injected (not the instance), allowing configuration. During the run phase and everywhere else, the instance produced by $get is injected.
privateprefix='Hello';// Configuration method — callable during config phase
setPrefix(value: string){this.prefix=value;}// The injector calls $get to produce the service instance
$get=['$log',($log: ng.LogService)=>{constprefix=this.prefix;return{greet(name: string){$log.info(`${prefix}, ${name}!`);},};}];}angular.module('myApp',[]).provider('greeter',GreeterProvider).config(['greeterProvider',function(greeterProvider){// During config, the *provider* is injected — note the "Provider" suffix
greeterProvider.setPrefix('Greetings');}]).run(['greeter',function(greeter){// During run, the *instance* is injected
greeter.greet('world');}]);
Info: During the config phase, inject a provider by appending Provider to its name: greeterProvider for the greeter service. This naming convention is enforced by AngularTS internally.
Decorating existing services
A decorator intercepts an existing service and can replace, wrap, or augment it. The original instance is available as $delegate.
Config blocks can inject providers and constants only. Run blocks have access to all services.
// Config — providers only
app.config(['$httpProvider',function($httpProvider){$httpProvider.defaults.headers.common['X-App']='myApp';}]);// Run — services are available
app.run(['$rootScope','$state',function($rootScope,$state){$rootScope.$on('$stateChangeError',()=>$state.go('error'));}]);
$injector API reference
Method
Description
$injector.get(token)
Returns the service instance for token. Throws if not found.
$injector.has(token)
Returns true if a provider for token is registered.
$injector.invoke(fn, self?, locals?)
Calls fn with injected arguments. Optionally overrides specific tokens with locals.
$injector.instantiate(Type, locals?)
Instantiates a constructor with new, injecting its dependencies.
$injector.annotate(fn)
Returns the array of dependency names for fn.
$injector.loadNewModules(mods)
Loads additional modules into a running injector.
2.4 - Modules: organizing your AngularTS application
Learn how AngularTS modules group controllers, services, directives, and config into composable units that the injector loads at bootstrap.
Every AngularTS application is assembled from one or more modules. A module is a named container that registers services, directives, controllers, filters, and configuration blocks. Modules do not execute any code themselves — they record recipes that the injector later uses to construct and wire together your application. This separation between declaration and instantiation is what makes AngularTS applications easy to test and compose.
Creating and retrieving modules
Use angular.module() to both create and look up modules. The presence of the second argument — the requires array — is what distinguishes creation from retrieval.
TypeScript
// Create a new module with no dependencies
constapp=angular.module('myApp',[]);// Retrieve an already-registered module
constsame=angular.module('myApp');
JavaScript
// Create a new module
varapp=angular.module('myApp',[]);// Retrieve it elsewhere (e.g., in another file)
varsame=angular.module('myApp');
Warning: Calling angular.module('myApp', []) a second time replaces the existing module. Always pass the requires array only once — at the point of creation — and omit it everywhere else.
Module registration methods
The NgModule instance returned by angular.module() exposes a fluent API for registering every kind of application artifact. All methods return the same module so calls can be chained.
.controller(name, fn)
Registers a controller constructor. The controller is instantiated by $controller and receives a child scope.
.service(name, ctor)
Registers a singleton service constructed with new. The constructor is instantiated once and reused.
.factory(name, fn)
Registers a factory function whose return value becomes the singleton. The function must not return undefined.
.provider(name, type)
Registers a full provider. The provider’s $get method is called to produce the service instance. Providers can expose configuration methods accessible during the config phase.
.value(name, val)
Registers an arbitrary value as a service. Values cannot be injected during the config phase.
.constant(name, val)
Registers a constant that is available during both the config and run phases and cannot be overridden by a decorator.
.directive(name, fn)
Registers a directive factory for the $compile provider.
.filter(name, fn)
Registers a filter function for use in templates and $filter.
.config(fn)
Runs during the config phase, before any services are instantiated. Only providers and constants can be injected.
.run(fn)
Runs after the injector has been created. Services are available. Use this for one-time initialization logic.
.state(definition) / .state(name, definition)
Registers a router state through $stateProvider during the config phase. This
is equivalent to using .config(['$stateProvider', ...]), but keeps route
declarations in the same fluent module chain as components and services.
The method records only a provider-token invocation; it does not import router
implementation code into custom runtimes unless that runtime actually includes
the router provider and loads a module that calls .state().
A complete module example
The following example creates a module, registers a constant, a service, a controller, and a config block, then composes that module with a second utility module.
The requires array lists the names of other modules that must be loaded before the current one. The injector resolves the entire dependency graph recursively before running any config or run blocks.
'ng',// AngularTS core — always auto-loaded but explicit is fine
'util',// local utility module
'ngRoute',// third-party module
]);
Modules are loaded in dependency order, depth-first. If two modules declare the same service, the last one registered wins.
The built-in ng module
The ng module is registered automatically when the Angular class is instantiated. You never need to declare it as a dependency — it is always prepended to the bootstrap module list. It provides every core service and directive, including:
Token
Description
$rootScope
The root of the scope hierarchy
$compile
Template compiler
$http
HTTP client
$interpolate
Template interpolation
$parse
Expression parser
$filter
Filter registry
$animate
Animation support
$location
URL management
$machine
Reactive mode machines
$sce
Strict contextual escaping
$state
Router state service
$eventBus
Pub/sub messaging
Tip: Splitting your application into small, focused modules makes unit testing dramatically easier. Each module can be loaded in isolation with angular.injector(['ng', 'myModule']), giving you a fully functional injector without bootstrapping the DOM.
Special module methods
Beyond the standard registration methods, NgModule supports several higher-level conveniences:
// Register an injectable reactive mode machine
app.machine('sessionMachine',{initial:'setup',data:{},transitions:{},});// Register machine/workflow config from DI-backed factories
app.value('settings',{sessionMode:'setup',});functionmachineConfig(settings){return{initial: settings.sessionMode,data:{roomId:''},transitions:{setup:{join(data,message){data.roomId=message.roomId;return'waiting';},},},};}machineConfig.$inject=['settings'];app.machine('sessionMachine',machineConfig);functionworkflowConfig(settings){return{id:'onboarding',initial:'idle',data:{sessionMode: settings.sessionMode},transitions:{idle:{start(data){data.sessionMode='running';return'running';},},},};}workflowConfig.$inject=['settings'];app.workflow('onboardingWorkflow',workflowConfig);app.wasm('mathLib','/wasm/math.wasm',{});// Register a Web Worker connection
app.worker('backgroundWorker','/workers/bg.js');// Register a REST resource backed by $rest
app.rest('Post','/api/posts',Post);// Register a persisted service (session, local, or cookie storage)
app.store('prefs',UserPreferences,'local');// Register a pre-configured SSE stream
app.sse('notifications','/events/stream');// Register a pre-configured WebSocket connection
app.websocket('chat','wss://chat.example.com/ws');
These methods all push entries onto the module’s internal invoke queue. They are resolved by the injector during bootstrap exactly like any other $provide registration.
2.5 - Scopes, data binding, and the scope hierarchy
Explore how AngularTS scopes work as reactive ES6 Proxies, how the hierarchy flows from $rootScope, and how to use events and watchers effectively.
A scope in AngularTS is the glue between the model and the view. It is a plain JavaScript object wrapped in an ES6 Proxy so that property assignments automatically trigger DOM updates without any manual notification. Every controller, directive, and component operates against a scope, and those scopes are organized into a tree rooted at $rootScope.
What a scope actually is
When you write $scope.count = 0 in a controller, AngularTS is not storing count on a special object — it is storing it on an ordinary JavaScript object. The Proxy layer intercepts the set trap and, whenever a watched property changes, schedules the affected binding listeners to re-evaluate on the next microtask.
set(target,property,value,proxy):boolean{// ... after storing the value ...
constlisteners=this._watchers.get(property);if(listeners){this._scheduleListener(listeners);// queues a microtask flush
}returntrue;}
The result is that you write natural JavaScript assignments and the DOM stays in sync — no $apply() call required for synchronous code paths.
Creating scopes
Scopes are created by the framework, not by application code. The injector creates $rootScope when the ng module loads. Each ng-controller directive, isolate directive, and ng-repeat iteration creates a child scope derived from its parent.
You can create child scopes manually when building custom directives:
constchild=$scope.$new();// Isolate child — does not inherit watchable properties
constisolate=$scope.$newIsolate();// Transcluded child — linked to an outer parent scope
consttranscluded=$scope.$transcluded(outerScope);
Info:$scope.$new() sets the new scope’s prototype to the parent’s underlying target object. Reading a property that does not exist locally will walk the prototype chain, just like plain JavaScript objects.
The scope hierarchy
Every scope holds a reference to $root (the root scope) and $parent (the scope that created it). Child scopes are tracked in the _children array.
You can search for a named scope from anywhere in the tree:
$scope.$scopename='userPanel';// Find it from $rootScope
constpanel=$rootScope.$searchByName('userPanel');// Or via the angular instance
constpanel2=angular.getScopeByName('userPanel');
Scope events
Scopes communicate across the hierarchy through a lightweight event system. Events travel either upward or downward — never both directions at once.
$emit — upward
// Fire an event from a child scope upward toward $rootScope
$scope.$emit('user:selected',{id: 42});// A parent scope listens
$scope.$on('user:selected',function(event,user){console.log('Selected user ID:',user.id);});
$broadcast — downward
// Broadcast from $rootScope down to all descendants
$rootScope.$broadcast('config:updated',newConfig);// Any child scope can listen
$scope.$on('config:updated',function(event,config){$scope.theme=config.theme;});
The $on method returns a deregistration function. Call it when the listener is no longer needed:
// Later, when the listener should stop
deregister();
Stopping propagation
$emit propagation can be stopped before it reaches $rootScope:
event.stopPropagation();// stops upward travel
event.preventDefault();// signals that the default was prevented
});
Watching scope properties
In the reactive proxy model, you rarely need $watch — template bindings update automatically. Use $watch when you need to run side-effect code in response to a data change, such as syncing to an external library or triggering a service call.
constderegister=$scope.$watch('searchQuery',function(newValue,target){if(newValue){searchService.query(newValue).then(results=>{$scope.results=results;});}});// Lazy watch — skips the initial call, only fires on changes
$scope.$watch('count',function(newValue){console.log('count changed to',newValue);},/* lazy */true);// Stop watching when done
deregister();
Note:$watch on a constant expression (a literal string or number) is evaluated once and the deregistration function is a no-op. The runtime detects this via the _constant flag on the compiled expression.
Watchable expression types
$watch accepts any expression that $parse can compile — identifiers, member expressions, binary comparisons, function calls, array and object literals, and conditional expressions.
$scope.$watch('count > 10',handler);// binary expression
$scope.$watch('items.length',handler);// member on array
$scope.$watch('getTotal()',handler);// function call
$scope.$watch('a || b',handler);// logical expression
$scope.$watch('[firstName, lastName]',handler);// array expression
Merging scope state
// $merge copies properties from a plain object into the scope
$scope.$merge({name:'Alice',age: 30});
Destroying a scope
When a controller’s element is removed from the DOM, AngularTS calls $destroy() on the associated scope. You can also call it manually. Destroying a scope:
Broadcasts $destroy downward to all children.
Removes all watcher registrations for this scope’s ID from the shared _watchers map.
Clears all $on listeners.
Removes itself from the parent’s _children array.
Sets _destroyed = true and nulls internal references on the next microtask.
consttempScope=$rootScope.$new();tempScope.data=loadSomething();// When done:
tempScope.$destroy();
Warning: Do not read from or write to a scope after calling $destroy(). The scope’s property map is reduced to a minimal tombstone on the next microtask.
Relationship to controllers and directives
Each ng-controller directive asks $scope.$new() to create a child scope and passes it to the controller constructor as $scope. The controller writes model properties directly onto that scope:
$scope.count=0;$scope.increment=function(){$scope.count+=1;// Proxy intercepts; DOM updates automatically
};}]);
Directives with scope: true get an inherited child scope; directives with scope: {} get an isolate scope. The isolate scope does not walk the parent prototype chain for watchable properties, but it can still receive values through explicit bindings.
Scope API quick reference
Method
Description
$scope.$new(child?)
Creates an inherited child scope.
$scope.$newIsolate(instance?)
Creates an isolate child scope.
$scope.$watch(expr, fn, lazy?)
Registers a watcher; returns a deregistration function.
$scope.$on(name, fn)
Registers an event listener; returns a deregistration function.
$scope.$emit(name, ...args)
Fires an event upward through the hierarchy.
$scope.$broadcast(name, ...args)
Fires an event downward to all descendants.
$scope.$merge(obj)
Copies enumerable properties from obj into the scope.
$scope.$destroy()
Tears down the scope and all its watchers.
$rootScope.$searchByName(name)
Finds a scope by its $scopename anywhere in the tree.
$scope.$getById(id)
Finds a scope by numeric ID within the subtree.
2.6 - Templates, interpolation, and expression parsing
Master the {{ }} interpolation syntax, one-time bindings, filter pipes, and how $interpolate and $parse power programmatic expression evaluation.
Templates in AngularTS are ordinary HTML files augmented with a handful of special syntax forms. The most fundamental is interpolation: the {{ expression }} delimiters that tell the template compiler to evaluate an expression against the current scope and render its result as text. The $interpolate service handles this translation at compile time, and the reactive proxy system ensures the DOM re-renders whenever the underlying data changes.
Interpolation syntax
Place any valid AngularTS expression between {{ and }} to render its current value:
The expression is parsed by $parse, evaluated against the current scope, and the result is stringified and inserted into the text node. If the expression throws, $interpolate catches and routes the error through $exceptionHandler.
What expressions can contain
AngularTS expressions are a safe subset of JavaScript. They support:
Property access
user.profile.name, items[0].label
Method calls
format(date), list.filter(fn)
Arithmetic and comparison
count * price, score >= 100
Logical operators
isAdmin || isMod, name && name.length
Ternary
flag ? 'yes' : 'no'
Array and object literals
[a, b, c], { key: value }
Expressions cannot contain new, delete, typeof, void, assignment operators, or any access to the global scope. This sandbox keeps templates safe against inadvertent or malicious code execution.
Filters in templates
Apply a filter to an expression using the pipe character |. Filters transform the value before it is rendered. You can chain multiple filters:
<p>Price: {{ product.price | currency:'USD' }}</p><!-- Sort a list by a property --><ling-repeat="item in items | orderBy:'name'">{{ item.name }}</li><!-- Limit a list and filter it by a search term --><ling-repeat="item in items | filter:search | limitTo:10"> {{ item.title }}
</li><!-- Date formatting --><span>{{ event.date | date:'longDate' }}</span><!-- Chained filters --><p>{{ message | uppercase | limitTo:50 }}</p>
Filters receive the value as their first argument and any parameters after the colon as subsequent arguments. They are pure functions — given the same input, they always produce the same output, which lets the reactive system cache their results.
One-time bindings
Prefix an expression with :: to evaluate it once and then release the binding. This is a performance optimization for data that is set during initialization and never changes:
<h1>{{ ::pageTitle }}</h1><p>User ID: {{ ::user.id }}</p><!-- Inside ng-repeat — binds each item once --><ling-repeat="item in ::staticList">{{ ::item.name }}</li>
Tip: Use one-time bindings for any data that is effectively constant after initialization: configuration values, user identity, translated strings, or items loaded once at startup. They reduce the number of active watchers and improve scroll performance in long lists.
The $interpolate service
The $interpolate service is what $compile uses internally to process interpolation expressions in templates. You can use it directly when you need to evaluate an interpolation string programmatically.
'$scope','$interpolate',function($scope,$interpolate){// Compile a template string into a reusable function
constgreetFn=$interpolate('Hello, {{ name }}! You have {{ count }} messages.');$scope.name='Alice';$scope.count=5;// Evaluate the template against a context object
constresult=greetFn($scope);// → "Hello, Alice! You have 5 messages."
// The interpolation function exposes the raw expressions it found
console.log(greetFn.expressions);// ['name', 'count']
console.log(greetFn.exp);// 'Hello, {{ name }}! You have {{ count }} messages.'
},]);
$interpolate parameters
text: string,mustHaveExpression?: boolean,// return undefined if no {{ }} found
trustedContext?: SceContext,// SCE context for security checking
allOrNothing?: boolean,// return undefined if any expression is undefined
):InterpolationFunction|undefined
The returned InterpolationFunction is callable with (context, cb?). When cb is provided, $interpolate sets up $watch calls on the scope so cb is invoked whenever any expression in the template changes.
// Watch mode: cb fires on every change
fn($scope,(newValue)=>{titleElement.textContent=newValue;});
Customizing the delimiters
The default delimiters are {{ and }}. Configure them via $interpolateProvider in a config block:
After this change, templates use {[ expression ]} instead. This is useful when you are embedding AngularTS in a server-side template engine that already uses {{ (such as Jinja2 or Handlebars).
The $parse service
$parse is the lower-level primitive beneath $interpolate. It compiles a single expression string into a CompiledExpression function that can be called with a context:
'$scope','$parse',function($scope,$parse){$scope.user={name:'Bob',score: 42};// Compile once, call many times
constgetScore=$parse('user.score');console.log(getScore($scope));// 42
// Expressions with assign support two-way binding
constnameParse=$parse('user.name');nameParse.assign($scope,'Carol');console.log($scope.user.name);// 'Carol'
// Parsed expressions are cached — repeated calls with the same
// string return the same compiled function object
constgetScore2=$parse('user.score');console.log(getScore===getScore2);// true
},]);
Compiled expression properties
Property
Type
Description
_constant
boolean
true if the expression is a literal constant
_literal
boolean
true if the expression is a simple literal
_assign
function?
Present for l-value expressions; assigns a value to the context
_inputs
any[]?
Sub-expressions tracked for change detection
_decoratedNode
BodyNode
The annotated AST for this expression
Security and SCE
When binding HTML content directly into the DOM, AngularTS enforces Strict Contextual Escaping (SCE). Plain interpolation always produces text, never HTML. To bind HTML you must use ng-bind-html with a trusted value:
<p>{{ userComment }}</p><!-- To render HTML, mark it as trusted first --><png-bind-html="trustedHtml"></p>
'$scope','$sce',function($scope,$sce){// Explicitly trust HTML from a known-safe source
$scope.trustedHtml=$sce.trustAsHtml('<strong>Bold</strong> text');},]);
Warning: Never call $sce.trustAsHtml() on user-provided input. Only use it on HTML that your application controls — such as server-rendered content that has already been sanitized.
Escaping interpolation delimiters
If you need to display literal {{ in a template without triggering interpolation, escape each character with a backslash:
<p>The syntax is \{\{ expression \}\}</p>
$interpolate unescapes these sequences before returning the final string.
3 - Directive Reference
3.1 - ng-repeat
Complete reference for ng-repeat: iterating arrays and objects, track by, special scope variables, filters, multi-element repeat, and performance guidance.
ng-repeat instantiates a template for each item in a collection, creating a child scope for every element. It is the primary directive for rendering lists and grids in AngularTS.
Basic syntax
<ling-repeat="item in items">{{ item.name }}</li><!-- Iterate an object (key-value pairs) --><trng-repeat="(key, value) in user"><td>{{ key }}</td><td>{{ value }}</td></tr>
ng-repeat
Type:expression
Required: yes
One of these forms:
item in collection — iterate array or array-like
(key, value) in object — iterate object properties
item in collection track by expression — with explicit tracking
item in collection | filter:fn — with inline filter
Special scope variables
Every ng-repeat child scope exposes these read-only properties:
$index
Type:number
Zero-based position of the item in the collection.
By default, ng-repeat tracks items by object identity. When the collection changes, it destroys and recreates DOM nodes for items that aren’t the same object reference. track by lets you specify a stable key, dramatically improving performance when data is re-fetched from a server.
<ling-repeat="user in users track by user.id">{{ user.name }}</li><!-- Track by $index — useful for arrays of primitives --><ling-repeat="tag in tags track by $index">{{ tag }}</li>
Warning: Do not use track by $index when items can be reordered or deleted — it causes incorrect DOM reuse. Use a stable unique ID instead.
Filtering and sorting
Apply filters inline in the ng-repeat expression:
<ling-repeat="item in items | filter:searchText">{{ item.name }}</li><!-- Filter by object (matches any field) --><ling-repeat="item in items | filter:{ category: 'books' }">{{ item.name }}</li><!-- Sort ascending --><ling-repeat="item in items | orderBy:'name'">{{ item.name }}</li><!-- Sort descending --><ling-repeat="item in items | orderBy:'-price'">{{ item.name }}</li><!-- Limit to first 10 --><ling-repeat="item in items | limitTo:10">{{ item.name }}</li><!-- Chain filters --><ling-repeat="item in items | filter:query | orderBy:'name' | limitTo:20"> {{ item.name }}
</li>
Multi-element repeat
Use ng-repeat-start and ng-repeat-end to repeat a block of sibling elements (not just a single element):
<ddng-repeat-end>{{ def.description }}</dd>
This produces alternating <dt> / <dd> pairs, one for each item in definitions.
Animating ng-repeat
ng-repeat integrates with $animate. Added items receive .ng-enter, removed items .ng-leave, and moved items .ng-move CSS classes:
Always use track by with a unique ID for large lists.
Avoid complex expressions in ng-repeat — compute derived values in the controller.
Use limitTo to paginate rather than rendering thousands of items.
One-time bind static content: {{ ::item.name }} avoids watches on items that never change.
3.2 - ARIA directives
This is covered by the ARIA provider, which
documents all supported aria-* behavior and related configuration.
Use the provider page if you need details about global ARIA support and defaults.
3.3 - Form directives
API reference for form, ng-form, validation, and ng-messages directives.
AngularTS enhances native HTML forms with a form controller that tracks validity and user interaction state. The form and ng-form directives attach this controller to the scope, and the built-in validators populate it automatically.
form / ng-form
A plain <form> element with a name attribute creates a FormController on the current scope. ng-form does the same but can be used on non-form elements or for nested forms.
Display validation error messages tied to a field’s $error object.
<divng-message="required">Email is required.</div><divng-message="email">Please enter a valid email address.</div><divng-message-default>This field has an error.</div></div>
ng-messages
Type:expression
Required: yes
Expression pointing to an $error object (typically formName.fieldName.$error).
ng-messages-multiple
Type:none
By default, only the first matching message is shown. Add this attribute to show all matching messages simultaneously.
ng-message
Type:string
Required: yes
The validator key to match against the $error object. Shown when $error[key] is truthy.
ng-message-exp
Type:expression
Same as ng-message but evaluates an expression rather than a string literal.
ng-message-default
Type:none
Shown when no other ng-message matches. Useful as a generic fallback.
Complete form example
<div><label>Email</label><inputname="email"type="email"ng-model="user.email"required><divng-messages="signupForm.email.$error"ng-show="signupForm.email.$dirty"><divng-message="required">Required.</div><divng-message="email">Invalid email format.</div></div></div><div><label>Password</label><inputname="password"type="password"ng-model="user.password"requiredminlength="8"><divng-messages="signupForm.password.$error"ng-show="signupForm.password.$dirty"><divng-message="required">Required.</div><divng-message="minlength">Must be at least 8 characters.</div></div></div><buttontype="submit"ng-disabled="signupForm.$invalid">Sign Up</button></form>
3.4 - ng-app
Bootstrap AngularTS application
Description
Use this directive to auto-bootstrap an AngularTS application. The ng-app
directive designates the root element of the application and is typically placed
near the root element of the page - e.g. on the <body> or <html> tags.
3.5 - ng-bind
Sync or hydrate textContent of element with an expression
Description
The ng-bind attribute places the text content of the specified HTML element
with the value of a given expression, and to update the text content when the
value of that expression changes.
Typically, you don’t use ng-bind directly, but instead you use the double
curly markup like {{ expression }} which is similar but less verbose.
It is preferable to use ng-bind instead of {{ expression }} if a template is
momentarily displayed by the browser in its raw state before it is compiled.
Since ng-bind is an element attribute, it makes the bindings invisible to the
user while the page is loading.
An alternative solution to this problem would be using the ng-cloak directive.
ng-bind can be modified with a data-lazy data attribute (or shorthand lazy
attribute), which will delay update of element content until model is changed.
This is useful for rendering server-generated content, while keeping the UI
dynamic. In other frameworks, this technieque is known as
hydration.
Description: Expression to evaluate and modify
textContent
property.
Example:
<divng-bind="name"></div>
Directive modifiers
data-lazy
Type: N/A
Description: Apply expression once the bound model changes.
Example:
<divng-bind="name"data-lazy></div><!-- or --><divng-bind="name"lazy></div>
Demo
<sectionng-app><!-- Eager bind --><label>Enter name: <inputtype="text"ng-model="name"/></label><br/> Hello <spanng-bind="name">I am never displayed</span>!
<!-- Lazy bind with short-hand `lazy` --><buttonng-click="name1 = name">Sync</button><spanng-bind="name1"lazy>I am server content</span>!
</section>
Hello I am never displayed!
I am server content!
3.6 - ng-bind-html
Bind trusted HTML content to an element.
Sets the innerHTML of an element to a trusted HTML string. The value must be explicitly trusted through the $sce service to prevent XSS.
Expression that evaluates to a value marked as trusted HTML via $sce.trustAsHtml(). Untrusted strings will throw an SCE error.
Warning: Never pass user-supplied content directly to $sce.trustAsHtml(). Only trust HTML you control or have saniti
3.7 - ng-bind-template
Bind interpolated template text to an element.
Binds a template string that may contain multiple {{ }} interpolation expressions. Useful on attributes or when you need mixed text and expressions in the element’s text content.
ng-bind-template
Type:string
Required: yes
A string literal containing one or more {{ expression }} interpolations. The entire string is interpolated and set as textContent.
3.8 - ng-blur
Handler for blur event
Description
The ng-blur directive allows you to specify custom behavior when an element
loses focus.
Description: Expression to evaluate upon
blur
event.
FocusEvent
object is available as $event.
Example:
<divng-blur="$ctrl.handleBlur($event)"></div>
Demo
<sectionng-app><inputtype="text"ng-blur="count++"ng-init="count = 0"placeholder="Click or tab away from me"/> Lost focus {{ count }} times
</section>
Lost focus {{ count }} times
3.9 - ng-channel
Subscribe a template to a messaging service topic
Description
Updates element’s content by subscribing to events published on a named channel
using $eventBus.
If the element does not contain any child elements or templates, the
directive will replace the element’s inner HTML with the published value.
If the element does contain a template and the published value is an
object, the directive will merge the object’s key-value pairs into the
current scope, allowing Angular expressions like to be evaluated and
rendered.
The directive automatically unsubscribes from the event channel when the scope
is destroyed.
Parameters
ng-channel
Type:string
Description: The name of the channel to subscribe to using $eventBus.
Dynamically bind one or more CSS classes using expressions.
Description
The ng-class directive allows dynamically setting CSS classes on an HTML
element by binding to an expression. The directive supports the following
expression types:
String — space-delimited class names.
Object — keys as class names and values as booleans. Truthy values add the
class.
Array — containing strings and/or objects as described above.
For complex view state, bind a precomputed class map instead of embedding a long
object expression in the template:
Important: Avoid using interpolation ({{ ... }}) in the value of the
class attribute together with ng-class. See
interpolation known issues for
details.
Animations
If data-animate attribute is present, the following animations will be applied
to the element:
The ng-cloak directive is used to prevent the HTML template from being briefly
displayed by the browser in its raw (uncompiled) form while your application is
loading. Use this directive to avoid the undesirable flicker effect caused by
the HTML template display.
The directive can be applied to the <body> element, but the preferred usage is
to apply multiple ng-cloak directives to small portions of the page to permit
progressive rendering of the browser view.
ng-cloak works in cooperation with the following CSS rule:
The ng-el directive allows you to store a reference to a DOM element in the
current scope, making it accessible elsewhere in your template or from your
controller. The reference is automatically removed if the element is removed
from the DOM.
Use ng-el for the common case where you want the native element itself:
<sectionng-controller="BoardController as $ctrl"><canvasng-el="$ctrl.boardEl"></canvas></section>
functionBoardController(){this.boardEl=null;}
Use a bare name for simple scope shorthand:
<canvasng-el="boardEl"></canvas>
Use a full assignable expression for controller-as or object-path refs:
For simple DOM element references, ng-el is the clearer API.
Parameters
ng-el
Type:string (optional)
Description: Name of the key under which the element will be stored in
scope, or an assignable expression such as $ctrl.boardEl. Bare names are
treated as shorthand keys. If omitted, the element’s id attribute will be
used.
<sectionng-app><divng-el="$chesireCat"></div><divng-elid="response"></div><buttonclass="btn"ng-el="$button"ng-click="
$chesireCat.innerHTML = '🐱';
response.innerHTML='That depends a good deal on where you want to get to.';
$button.hidden = true"> Which way I ought to go?
</button></section>
3.17 - ng-focus
Handler for focus event
Description
The ng-focus directive allows you to specify custom behavior when an element
is focused.
Description: Expression to evaluate upon
focus
event.
FocusEvent
object is available as $event.
Example:
<divng-focus="$ctrl.greet($event)"></div>
Demo
<sectionng-app><inputtype="text"ng-focus="count++"ng-init="count = 0"placeholder="Click or tab into me"/> Focused {{ count }} times
</section>
Focused {{ count }} times
3.18 - ng-get
Initiates a GET request
Description
The ng-get directive allows you to fetch content via $http service from a
remote URL and insert, replace, or manipulate it into the DOM. For DOM
manipulation to work, the response must be HTML content. If the server endpoint
returns a JSON-response, the directive will treat it as an object to be merged
into the current scope and the swap strategy will be ignored.
Example
<section><divng-get="/json">Get</div><!-- Enpoint returns {name: 'Bob'}--> {{ name }}
<!-- 'Bob' will be merged into current scope. --></section>
In case of error, the directive displays the error in place of success result or
will merge it into the current scope if response contains JSON.
Example
<section><divng-post="/json">Get</div><!-- Enpoint returns 404 with {error: 'Not found'}--> {{ error }}
<!-- 'Not found' will be merged into current scope. Nothing to swap --></section>
Additional options for request and response handling can be modified with
attributes provided below.
Parameters
ng-get
Type:string
Description: A URL to issue a GET request to
Example:
<divng-get="/example">get</div>
Modifiers
data-trigger
Type:string
Description: Specifies the DOM event for triggering a request (default is
click). For a complete list, see
UI Events. To
eagerly execute a request without user interaction, use the “load” event,
which is triggered syntheticaly on any element by the directive linking
function. This is in contract to the native
load,
which executes lazily only for window object and certain resource elements.
Description: Triggers a request whenever its value changes. This attribute
can be used with interpolation (e.g., {{ expression }}) to observe reactive
changes in the scope.
Example:
<divng-get="/example"latch="{{ latch }}"ng-mouseover="latch = !latch"> Get
</div>
Toggles the CSS display property of an element without removing it from the DOM. The element’s scope is always alive, regardless of visibility.
<divng-hide="isLoading">Content here</div>
ng-show
Type:expression
Required: yes
When truthy, the element is visible (removes the ng-hide CSS class). When falsy, the element is hidden.
ng-hide
Type:expression
Required: yes
Inverse of ng-show. When truthy, the element is hidden.
Animation hooks:.ng-hide-add / .ng-hide-add-active when hiding, .ng-hide-remove / .ng-hide-remove-active when showing.
ng-if vs ng-show/hide
Aspect
ng-if
ng-show / ng-hide
DOM presence
Removed when false
Always in DOM
Scope lifetime
Destroyed when false
Always alive
Child watchers
Removed when false
Always active
Initial render cost
Only when true
Always rendered
Animation events
ng-enter / ng-leave
ng-hide-add / ng-hide-remove
Use ng-if when the content is expensive to render or when you want to prevent hidden content from making network requests. Use ng-show/hide when toggling frequently and you need instant re-display without re-initiali
3.20 - ng-if
Conditionally add or remove an element from the DOM.
Adds or removes an element from the DOM based on the truthiness of an expression. When the element is removed, its scope and all child scopes are destroyed. When re-added, a fresh scope is created.
Welcome back, {{ user.name }}!
</div>
ng-if
Type:expression
Required: yes
When truthy, the element is rendered. When falsy, the element and its scope are destroyed and removed from the DOM.
Animation hooks:.ng-enter / .ng-enter-active when added, .ng-leave / .ng-leave-active when removed.
Note:ng-if creates a child scope. If you bind ng-model inside an ng-if, write to an object property (obj.field) rather than a primitive to avoid scope shadowing issues.
3.21 - ng-include
Include a template
Description
3.22 - ng-inject
Inject dependencies into scope.
Description
The ng-inject directive injects registered injectables (services, factories,
etc.) into the current scope for direct access within templates or expressions.
This allows access to application state without having to create intermediary
controllers.
When applied to an element, the directive reads a semicolon-separated list of
injectables’ names from the ng-inject attribute and attempts to retrieve them
from the $injector. Each resolved injectable is attached to the current scope
under its corresponding name.
Parameters
ng-inject
Type:string
Restrict:A
Description: A semicolon-separated list of injectable’ names to attach to current scope.
Description: Expression to evaluate upon
keydown
event.
KeyboardEvent
object is available as $event.
Example:
<divng-keydown="$ctrl.greet($event)"></div>
Demo
<sectionng-app><inputtype="text"ng-keydown="count++"ng-init="count = 0"placeholder="Click here, then press down a key."/> Keydown {{ count }} times
</section>
Keydown {{ count }} times
3.24 - ng-keyup
Handler for keyup event
Description
The ng-keyup directive allows you to specify custom behavior when releasing
keys, regardless of whether they produce a character value.
Description: Expression to evaluate upon
keyup
event.
KeyboardEvent
object is available as $event.
Example:
<divng-keyup="$ctrl.greet($event)"></div>
Demo
<sectionng-app><inputtype="text"ng-keyup="count++"ng-init="count = 0"placeholder="Click here, then press down a key."/> Keyup {{ count }} times
</section>
Keyup {{ count }} times
3.25 - ng-load
Handler for load event
Description
The ng-load directive allows you to specify custom behavior for elements that
trigger
load
event.
Note: there is no guarantee that the browser will bind ng-load directive
before loading its resource. Demo below is using a large image to showcase
itself.
Description: Expression to evaluate upon
load
event. Event object
is available as $event.
Example:
<imgsrc="url"ng-load="$ctrl.load($event)"></div>
Demo
<sectionng-app><imgng-load="res = 'Large image loaded'"width="150px"src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Centroamerica_prehispanica_siglo_XVI.svg/1920px-Centroamerica_prehispanica_siglo_XVI.svg.png"/> {{ res }}
</section>
{{ res }}
3.26 - ng-model
Two-way data binding for form controls.
Binds the value of <input>, <textarea>, <select>, and custom controls to a scope expression.
<textareang-model="user.bio"></textarea><selectng-model="user.role"ng-options="r for r in roles"></select><inputtype="checkbox"ng-model="user.active">
ng-model
Type:expression
Required: yes
An assignable AngularTS expression. When the user changes the input, the expression is assigned the new value. When the scope value changes, the input is updated.
Model controller (NgModelController)
When ng-model is applied, AngularTS creates an NgModelController accessible as formName.fieldName on the scope. It exposes:
$viewValue
Type:any
The value as seen by the user in the input (always a string for text inputs).
$modelValue
Type:any
The value after parsers have run — what is stored on the scope.
$valid
Type:boolean
true when all validators pass.
$invalid
Type:boolean
true when any validator fails.
$pristine
Type:boolean
true until the user has interacted with this field.
$dirty
Type:boolean
true after the user has changed the value at least once.
$touched
Type:boolean
true after the field has received and lost focus.
$error
Type:object
Map of failing validator names to true. E.g., { required: true, minlength: true }.
Parsers and formatters
ng-model processes values through two pipelines:
Parsers ($parsers): Convert $viewValue → $modelValue. Applied on user input. Return undefined to mark invalid.
Formatters ($formatters): Convert $modelValue → $viewValue. Applied when scope value changes.
Configure update timing and validation behavior for ng-model.
Configures how and when ng-model reads and writes its value.
updateOn
Type:string
Space-separated list of DOM events that trigger a model update. Default is 'default' (uses the element’s natural update event). Common values: 'blur', 'change', 'keyup', 'default'.
<!-- Only update on blur --><inputng-model="name"ng-model-options="{ updateOn: 'blur' }"><!-- Update on both blur and custom event --><inputng-model="name"ng-model-options="{ updateOn: 'blur myEvent' }">
debounce
Type:number | object
Milliseconds to wait after the last change before updating the model. Can be a number (applies to all events) or an object mapping event names to delays.
<!-- 300ms debounce for all events --><inputng-model="search"ng-model-options="{ debounce: 300 }"><!-- Different debounce per event --><inputng-model="search"ng-model-options="{ debounce: { default: 300, blur: 0 } }">
allowInvalid
Type:boolean
When true, the model is updated even when validators fail. Default is false (model is set to undefined on invalid input).
getterSetter
Type:boolean
When true, the ng-model expression is treated as a getter/setter function rather than a plain property. The function is called with no arguments to get and with the new value to set.
Description: Expression to evaluate upon
mouseup
event.
MouseEvent
object is available as $event.
Example:
<divng-mouseup="$ctrl.greet($event)"></div>
Demo
<sectionng-app><divng-init="count = 0"ng-mouseup="count++">Mouse Up</div> Mouse Up {{ count }} times
</section>
Mouse Up
Mouse Up {{ count }} times
3.35 - ng-non-bindable
Stops compilation for element
Description
The ng-non-bindable directive tells the framework not to compile or bind the
contents of the current DOM element, including directives on the element itself
that have a lower priority than ngNonBindable. This is useful if the element
contains what appears to be directives and bindings but which should be ignored.
This could be the case if you have a site that displays snippets of code, for
instance.
ng-non-bindable
Type: N/A
Description: Stops compilation process for element
The ng-pointer-capture directive captures a pointer stream that starts on the
element and releases it when the pointer ends or is cancelled. This is useful
for board, canvas, and game-style interfaces where pointermove and pointerup
should continue reaching the same element even when the pointer leaves its
bounds.
ng-pointer-capture does not implement dragging behavior. It only manages the
browser pointer capture lifecycle. Use ng-on-pointerdown, ng-on-pointermove,
ng-on-pointerup, and ng-on-pointercancel for your application logic.
Parameters
ng-pointer-capture
Type: boolean attribute
Restrict:A
Element: ANY
Priority:1
Description: Calls setPointerCapture($event.pointerId) on pointerdown,
releases capture on pointerup and pointercancel, forgets browser-released
pointers on lostpointercapture, and releases active captures when the scope
is destroyed.
<style>.pointer-capture-demo{display:grid;gap:0.75rem;max-width:30rem;}.pointer-capture-demo__board{position:relative;aspect-ratio:16/9;overflow:hidden;border:1pxsolid#cbd5e1;background:linear-gradient(90deg,rgba(14,165,233,0.12)1px,transparent1px),linear-gradient(rgba(14,165,233,0.12)1px,transparent1px),#f8fafc;background-size:2rem2rem;touch-action:none;user-select:none;}.pointer-capture-demo__marker{position:absolute;left:0;top:0;width:1.5rem;height:1.5rem;border:2pxsolid#fff;border-radius:999px;background:#2563eb;box-shadow:00.5rem1remrgba(15,23,42,0.22);will-change:transform;}.pointer-capture-demo__status{margin:0;color:#475569;}</style><sectionng-app="pointerCaptureDemo"class="pointer-capture-demo"><divng-controller="PointerCaptureDemo as $ctrl"><divclass="pointer-capture-demo__board"ng-pointer-captureng-on-pointerdown="$ctrl.start($event)"ng-on-pointermove="$ctrl.move($event)"ng-on-pointerup="$ctrl.end($event)"ng-on-pointercancel="$ctrl.cancel()"data-event-prevent><divclass="pointer-capture-demo__marker"ng-style="$ctrl.markerStyle"></div></div><pclass="pointer-capture-demo__status">{{ $ctrl.status }}</p></div></section><script>window.angular.module('pointerCaptureDemo',[]).controller('PointerCaptureDemo',function(){this.dragging=false;this.status='Drag the marker across the board';this.markerStyle={transform:'translate(32px, 32px)',};this.positionFromEvent=function(event){constrect=event.currentTarget.getBoundingClientRect();constradius=12;constx=Math.max(radius,Math.min(event.clientX-rect.left,rect.width-radius),);consty=Math.max(radius,Math.min(event.clientY-rect.top,rect.height-radius),);this.markerStyle={transform:'translate('+(x-radius)+'px, '+(y-radius)+'px)',};};this.start=function(event){this.dragging=true;this.status='Pointer captured';this.positionFromEvent(event);};this.move=function(event){if(!this.dragging){return;}this.status='Dragging pointer '+event.pointerId;this.positionFromEvent(event);};this.end=function(event){if(this.dragging){this.positionFromEvent(event);}this.dragging=false;this.status='Pointer released';};this.cancel=function(){this.dragging=false;this.status='Pointer cancelled';};});</script>
{{ $ctrl.status }}
3.37 - ng-post
Initiates a POST request
Description
The ng-post directive allows you to send data via $http service to a remote
URL and insert, replace, or manipulate the server’s response into the DOM. The
directive assumes a response will be HTML content. If the server endpoint
returns a JSON-response, the directive will treat it as an object to be merged
into the current scope. In such a case, the swap strategy will be ignored and
the content will be interpolated into current scope. Unlike its sister ng-get
directive, ng-post assumes it is attached to a form, input, textarea, or
select element, which act as the source of data for request payload:
In case of error, the directive displays the error in place of success result or
will merge it into the current scope if response contains JSON. The behavior can
be combined with other directivs to create complex form-handling strategies.
Below is a form that dissappears in case of success or adds error state in case
of validation errors.
Additional options for request and response handling can be modified with
attributes provided below.
Parameters
ng-post
Type:string
Description: A URL to issue a GET request to
Example:
<divng-post="/example">post</div>
Modifiers
data-enctype
Type:string
Description: Specifies the content type of form. Defaults to
application/json. To send regular URL-encoded data form, use
application/x-www-form-urlencoded.
Description: Specifies the DOM event for triggering a request (default is
click). For a complete list, see
UI Events. To
eagerly execute a request without user interaction, use the “load” event,
which is triggered syntheticaly on any element by the directive linking
function. This is in contract to the native
load,
which executes lazily only for window object and certain resource elements.
Description: Triggers a request whenever its value changes. This attribute
can be used with interpolation (e.g., {{ expression }}) to observe reactive
changes in the scope.
Example:
<divng-post="/example"latch="{{ latch }}"ng-mouseover="latch = !latch"> Get
</div>
Toggles the CSS display property of an element without removing it from the DOM. The element’s scope is always alive, regardless of visibility.
<divng-hide="isLoading">Content here</div>
ng-show
Type:expression
Required: yes
When truthy, the element is visible (removes the ng-hide CSS class). When falsy, the element is hidden.
ng-hide
Type:expression
Required: yes
Inverse of ng-show. When truthy, the element is hidden.
Animation hooks:.ng-hide-add / .ng-hide-add-active when hiding, .ng-hide-remove / .ng-hide-remove-active when showing.
ng-if vs ng-show/hide
Aspect
ng-if
ng-show / ng-hide
DOM presence
Removed when false
Always in DOM
Scope lifetime
Destroyed when false
Always alive
Child watchers
Removed when false
Always active
Initial render cost
Only when true
Always rendered
Animation events
ng-enter / ng-leave
ng-hide-add / ng-hide-remove
Use ng-if when the content is expensive to render or when you want to prevent hidden content from making network requests. Use ng-show/hide when toggling frequently and you need instant re-display without re-initiali
3.39 - ng-sref
Create links to named router states.
Generates an href attribute pointing to a named state and handles click navigation. Equivalent to <a href="..."> but driven by state name rather than a raw URL.
<ang-sref="home">Go home</a><!-- State with parameters --><ang-sref="user.profile({ userId: user.id })">{{ user.name }}</a><!-- State with query params --><ang-sref="search({ q: 'angular', page: 1 })">Search</a>
ng-sref
Type:expression
Required: yes
State name, optionally followed by a params object in parentheses: "stateName" or "stateName({ param: value })". The expression is evaluated in the current scope.
ng-sref-opts
Type:object
Options passed to $state.go(). Common options: { reload: true }, { inherit: false }, { location: 'replace' }.
Animation hooks:.ng-enter / .ng-leave on matched/unmatched elements.
3.43 - ng-view
Render the active routed view.
Marks the element where the router renders the active state’s template. When the active state changes, the content inside ng-view is replaced with the new state’s template, compiled into a new scope.
<ng-view></ng-view><!-- As an attribute --><divng-view></div><!-- Named view (for multiple named views in one state) --><divng-view="sidebar"></div>
ng-view
Type:string
Optional view name. When omitted, this outlet renders the unnamed (default) view of the active state. When specified, renders the named view from the state’s views configuration.
States define their templates in $stateRegistry:
name:'home',url:'/home',template:'<h1>Home</h1>'});// Named views:
$stateRegistry.register({name:'dashboard',url:'/dashboard',views:{'':{template:'<p>Main content</p>'},'sidebar':{template:'<nav>Sidebar</nav>'}}});
3.44 - ng-window-* and ng-document-*
Handler for window and document events
Description
The ng-window-* and ng-document-* directives allow you to specify custom
behavior for events dispatched from the Window or Document object. The event
name is defined by including it in the placeholder of the directive name.
Example: ng-window-online binds to the window online event, and
ng-document-pointerup binds to the document pointerup event.
Listeners are removed automatically when the owning scope is destroyed.
<sectionng-app> In Chrome DevTools: Open <b>Network tab</b> → Select
<b>Throttling</b> dropdown -> Click <b>Offline</b> checkbox
<divng-window-online="online = true">Connected: {{ online }}</div><divng-window-offline="offline = true">Disconnected: {{ offline }}</div><buttonng-document-click="lastDocumentClick = $event.type"> Listen for next document click
</button><div>Document event: {{ lastDocumentClick || 'none' }}</div></section>
In Chrome DevTools: Open Network tab → Select
Throttling dropdown -> Click Offline checkbox
Connected: {{ online }}
Disconnected: {{ offline }}
Document event: {{ lastDocumentClick || 'none' }}
4 - Directive Guides
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.
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.
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.
Marks an explicit scope boundary. Useful for isolating a section of the page without a controller.
<p>Hello {{ user.name }}</p></div>
ng-init
Initializes scope variables inline in the template. Best suited for simple one-off values or prototyping.
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.
<sectionng-controller="BoardController as $ctrl"><canvasng-el="$ctrl.boardEl"></canvas></section>
functionBoardController(){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:
<canvasng-el="boardEl"></canvas>
If the value is omitted, AngularTS uses the element id.
<canvasid="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.
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.
functionBoardController(){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.
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.
Scroll-tracked content
</div>
ng-inject
Injects a named service directly into the scope, making it accessible in the template without a controller.
<!-- $http is now available in this scope --></div>
Lazy loading and performance
ng-viewport
Uses the browser’s Intersection Observer API to defer content rendering until the element enters the viewport. Ideal for below-the-fold content.
<!-- loadComments() is called once when this enters the viewport --><divng-repeat="comment in comments">{{ comment.text }}</div></div>
ng-viewport
Type:expression
Expression to evaluate when the element enters the viewport. Called once and not repeated.
ng-cloak
Prevents the browser from briefly displaying uncompiled template syntax ({{ }}) before AngularTS bootstraps. Add to the root element or any element with interpolation.
<divng-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.
4.2 - Animation Directives: ng-animate-swap and CSS Hooks
Use ng-animate-swap, ng-animate-children, and CSS class hooks to animate structural directives like ng-if, ng-repeat, and ng-show with the $animate service.
AngularTS integrates animations into the same lifecycle that drives structural directives. Rather than managing setTimeout calls or CSS transitions manually, you add the animate attribute to an element and AngularTS’s $animate service handles entry, exit, and class-change transitions — applying and removing CSS hook classes at the right moment in the digest cycle.
How $animate integrates with directives
Structural directives — ng-if, ng-repeat, ng-show, ng-hide, ng-switch, ng-include, and ng-animate-swap — all check whether an element carries animation data before manipulating the DOM. When the animate attribute is present on an element (detected via hasAnimate(element)), they delegate DOM operations to $animate instead of performing them directly:
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:
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:opacity0.25sease,transform0.25sease;}.card.ng-enter-active{opacity:1;transform:translateY(0);}/* Fade out when the element is removed */.card.ng-leave{opacity:1;transition:opacity0.2sease;}.card.ng-leave-active{opacity:0;}
ng-animate-swap
ng-animate-swap swaps between transcluded content blocks using enter/leave animations as a watched expression changes. It runs at priority 550 — after ng-if (600) but before most attribute directives.
Each time the watched expression changes, the old element is removed via $animate.leave and the new transcluded clone is inserted via $animate.enter. The previous scope is destroyed before the new clone is linked.
A more common pattern is using ng-animate-swap to animate between stateful view components:
The watched expression. Any time its value changes, the current transcluded block is removed with a leave animation and a new clone is entered. Use the for attribute alias interchangeably.
ng-animate-children
ng-animate-children propagates an animation-children flag to the element’s cache so that the $animate queue knows whether child elements should also be animated during parent transitions.
<divng-if="showPanel"ng-animate-children="true"><divclass="panel-header">Header</div><divclass="panel-body"ng-repeat="item in items">{{ item }}</div></div>
When ng-animate-children is set to "on" or "true" (or is present as an empty attribute), child animations run in parallel with the parent. Without it, the animation queue suppresses child animations while the parent is entering or leaving.
<ulng-repeat="group in groups"ng-animate-children><ling-repeat="item in group.items"class="list-item">{{ item }}</li></ul>
ng-animate-children
Type:string | none
Accepts "on", "true", or an empty attribute to enable child animations. Any other value (or an interpolated expression evaluating to a falsy string) disables child animations.
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.
<liclass="task-item"ng-repeat="task in tasks track by task.id"animate><spanng-bind="task.title"></span><buttonng-click="removeTask(task)">Remove</button></li></ul>
.controller('TaskCtrl',function($scope){$scope.tasks=[{id:1,title:'Design wireframes'},{id:2,title:'Write tests'},{id:3,title:'Deploy to staging'}];$scope.removeTask=function(task){constidx=$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:
{{ message }}
</div>
transition:opacity0.3sease,max-height0.3sease;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 via $animate
The $animateJs service allows you to register JavaScript-based animation hooks alongside CSS animations:
.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;returnfunction(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;}};});
{{ 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:
4.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, <spanng-bind="user.name"></span>!</p>
The implementation watches the expression on every digest. The lazy attribute defers the first watch until a digest is explicitly triggered:
<spanng-bind="heavyExpression"lazy></span>
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.
<titleng-bind-template="{{pageTitle}} — {{siteName}}"></title><!-- Equivalent using child elements (not possible inside <title>) -->
The directive uses attr.$observe to watch the already-interpolated string; Angular re-evaluates the interpolation on each digest and writes the result 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.
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.
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 scope
$parsers — pipeline from view to model (view → model transformation)
$formatters — pipeline from model to view (model → view transformation)
$validators — synchronous validator functions keyed by error name
$asyncValidators — async validator functions that return Promises
$error — 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.
<divng-class="{ active: isActive, 'text-danger': hasError }"> Status panel
</div>
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.
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.
ng-class-even / ng-class-odd
These variants apply classes only to even- or odd-indexed rows inside an ng-repeat.
<ling-repeat="item in items"ng-class-even="'row-even'"ng-class-odd="'row-odd'"> {{ item.name }}
</li></ul>
ng-class
Type:ng.ClassValue (string | ng.ClassMap | array)
Required: yes
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.
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.
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.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.
The form directive
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.
Keys are validator names; values are arrays of failing controls
$pending
object
Keys are validator names with pending async validators
CSS classes on forms
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:2pxsolid#ef4444;}input.ng-valid.ng-dirty{border:2pxsolid#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
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.
<!-- Shipping address group --><ng-formname="shippingForm"><inputname="street"ng-model="shipping.street"required/><inputname="city"ng-model="shipping.city"required/><png-if="shippingForm.$invalid">Please complete shipping address.</p></ng-form><!-- Billing address group --><ng-formname="billingForm"><inputname="street"ng-model="billing.street"required/><png-if="billingForm.$invalid">Please complete billing address.</p></ng-form><buttonng-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.
Input directives
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.
<label><inputtype="radio"ng-model="plan"value="free"/> Free
</label><label><inputtype="radio"ng-model="plan"value="pro"/> Pro
</label><label><inputtype="radio"ng-model="plan"value="enterprise"/> Enterprise
</label><p>Selected: {{ plan }}</p>
Select
<!-- Simple string options --><selectname="country"ng-model="user.country"required><optionvalue="">-- Choose a country --</option><optionvalue="us">United States</option><optionvalue="gb">United Kingdom</option></select><!-- Object options with ng-options --><selectng-model="selectedRole"ng-options="role.id as role.label for role in roles"><optionvalue="">-- 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.
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.
<inputtype="text"ng-model="user.phone"pattern="^\d{10}$"/><!-- Dynamic pattern from scope --><inputtype="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).
<divclass="field"><label>Email</label><inputtype="email"name="email"ng-model="user.email"required/><divng-messages="signupForm.email.$error"role="alert"><png-message="required">Email address is required.</p><png-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:
<png-message="required">Password is required.</p><png-message="minlength">At least 8 characters required.</p><png-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:
<png-message="pattern">Invalid format.</p><png-message-default>This field has an error.</p></div>
Reusable message templates
Use ng-messages-include to load a shared message template file:
<divng-messages-include="'/partials/common-messages.html'"></div><png-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:
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
Type:number | object
Milliseconds to wait before committing the view value. Can be an object mapping event names to delays: { 'blur': 0, 'default': 500 }.
allowInvalid
Type:boolean
When true, the model is updated even when the value is invalid (normally the model is set to undefined when validation fails).
getterSetter
Type:boolean
When true, the ng-model expression is treated as a function that acts as both getter and setter.
timezone
Type:string
Timezone offset for date/time input parsing, e.g. "UTC" or "+0530".
Complete form example
The following example demonstrates a registration form with multiple input types, validators, debouncing, and ng-messages error display.
<!-- Username --><divclass="field"><labelfor="username">Username</label><inputid="username"type="text"name="username"ng-model="form.username"ng-model-options="{ debounce: 300 }"requiredng-minlength="3"ng-maxlength="20"ng-pattern="/^[a-z0-9_]+$/"/><divng-messages="regForm.username.$error"ng-if="regForm.username.$touched || regForm.$submitted"><png-message="required">Username is required.</p><png-message="minlength">At least 3 characters.</p><png-message="maxlength">No more than 20 characters.</p><png-message="pattern">Only lowercase letters, numbers, and underscores.</p></div></div><!-- Email --><divclass="field"><labelfor="email">Email</label><inputid="email"type="email"name="email"ng-model="form.email"required/><divng-messages="regForm.email.$error"ng-if="regForm.email.$touched || regForm.$submitted"><png-message="required">Email is required.</p><png-message="email">Enter a valid email address.</p></div></div><!-- Password --><divclass="field"><labelfor="password">Password</label><inputid="password"type="password"name="password"ng-model="form.password"requiredng-minlength="8"/><divng-messages="regForm.password.$error"ng-if="regForm.password.$dirty"><png-message="required">Password is required.</p><png-message="minlength">At least 8 characters required.</p></div></div><!-- Terms acceptance --><divclass="field"><label><inputtype="checkbox"name="terms"ng-model="form.agreedToTerms"required/> I agree to the terms and conditions
</label><png-if="regForm.terms.$error.required && regForm.$submitted"> You must accept the terms.
</p></div><buttontype="submit"ng-disabled="regForm.$invalid && regForm.$submitted"> Create account
</button></form>
.controller('RegistrationCtrl',function($scope){$scope.form={};$scope.submitRegistration=function(){$scope.regForm.$setSubmitted();if($scope.regForm.$valid){// Call your API
console.log('Registering:',$scope.form);}};});
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 inspired by HTMX. 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 scope merging — all configured through HTML attributes.
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:
<buttonng-get="/api/user/1">Load user</button><p>{{ name }}</p>
When the server returns JSON, the directive merges it into scope automatically. When it returns HTML, the result is compiled and injected into the DOM 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).
<buttonng-get="/api/weather?city=London"> Get weather
</button>{{ temperature }}°C — {{ description }}
<buttonng-get="/partials/user-card.html"swap="outerHTML"target="#user-area"> Show profile
</button><divid="user-area"></div>
Automatic trigger
Use trigger="load" to fire the request immediately when the element is linked (no user interaction required):
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.
<buttonng-post="/api/cart/add"success="cartMessage = $res.message"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:
ng-sse opens a persistent Server-Sent Events connection using the $sse service. Incoming messages are handled the same way as HTTP responses: JSON payloads are merged into scope, HTML strings are injected using the configured swap strategy.
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.
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.
Expression evaluated when the response has a 4xx or 5xx status code. The response data is available as $res.
<buttonng-post="/api/login"success="redirect('/dashboard')"error="loginError = $res.message"> Log in
</button>
state-success
Type:string
Router state name to navigate to on success (calls $state.go).
state-error
Type:string
Router state name to navigate to on error (calls $state.go).
animate
Type:none
When present, enables $animate transitions for the swap operation. Requires the $animate CSS hooks to be defined.
enctype
Type:string
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
<thead><tr><th>Name</th><th>Status</th><th>Joined</th></tr></thead><tbodyng-get="/api/users"trigger="load"swap="innerHTML"><!-- Populated with server-rendered rows --></tbody></table>
Infinite scroll
<ling-repeat="post in posts">{{ post.title }}</li></ul><buttonng-get="/api/posts?page={{ nextPage }}"ng-viewporton-enter="loadMore()"swap="beforeend"target="#post-list"> Load more
</button>
Real-time notifications via SSE
<spanng-bind="notifications.unread"></span></div><!-- SSE merges JSON payloads into scope automatically --><divng-sse="/api/events/notifications"trigger="load"></div>
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.
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.
<ling-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.
Master AngularTS structural directives including ng-if, ng-show, ng-hide, ng-repeat with track by, 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.
<divng-if="user.role === 'admin'"><h2>Admin Panel</h2><p>Welcome, {{ user.name }}. You have full access.</p></div>
<divng-if="isLoggedIn"><p>Welcome back, {{ user.name }}!</p><buttonng-click="logout()">Log out</button></div><divng-if="!isLoggedIn"><p>Please <ahref="/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.
<divng-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.
<divng-hide="isLoading"><p>Content is ready.</p></div><divng-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.
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
<ling-repeat="product in products"><strong>{{ product.name }}</strong> — ${{ product.price }}
<spanng-if="$first">(newest)</span><spanng-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.
<dtng-repeat="(key, value) in user">{{ key }}</dt><dd>{{ value }}</dd></dl>
Track by
By default, ng-repeat tracks items by identity (hashKey). When the collection changes, AngularTS tries to reuse existing DOM nodes by matching on the track key. The track by clause lets you provide a stable identity for items, which dramatically improves performance when working with large lists or when items are replaced by new objects from the server.
<divng-repeat="user in users">{{ user.name }}</div><!-- With track by id — DOM nodes for unchanged users are reused --><divng-repeat="user in users track by user.id">{{ user.name }}</div><!-- Track by $index — useful for arrays of primitives --><divng-repeat="tag in tags track by $index">{{ tag }}</div>
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><ling-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:
Warning: Duplicate track keys in the same repeater throw an ngRepeat:dupes error. Use track by $index or a unique property like track by item.id to guarantee uniqueness.
ng-repeat
Type:string
Required: yes
Expression in one of the forms:
item in collection
(key, value) in object
item in collection track by expression
item 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.
<divng-switch-when="active"><p>Account is active. Welcome, {{ user.name }}!</p></div><divng-switch-when="suspended"><p>Your account has been suspended. Please contact support.</p></div><divng-switch-when="pending"><p>Your account is awaiting verification.</p></div><divng-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:
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
Type:none
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.
<divng-include="'/partials/user-profile.html'"></div><!-- Include a dynamic template based on user role --><divng-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
Expression evaluating to the URL of the template to load. The URL is fetched via $templateRequest (which uses the template cache if available).
onload
Type:expression
Expression evaluated after the template is compiled and inserted.
autoscroll
Type:expression
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.
<preng-non-bindable><p>Use {{ expression }} to interpolate values.</p><div ng-bind="myValue"></div></pre>
<divng-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.
5 - Providers
5.1 - $anchorScrollProvider
Configure automatic anchor scrolling when the URL hash changes.
$anchorScrollProvider controls whether $anchorScroll reacts automatically
when $location changes the URL hash.
Use $ariaProvider to choose which accessibility attributes AngularTS manages
for common directives such as ng-show, ng-hide, ng-model, and disabled
controls.
Use provider defaults for application-wide settings such as cookie path,
HTTPS-only behavior, and SameSite policy. Per-call options still override these
defaults.
$eventBusProvider creates the injectable $eventBus singleton and exposes the
same instance through the global Angular service for integrations outside
dependency injection.
Most applications should use the default PubSub instance. Replace it only when
you need custom dispatch, instrumentation, or compatibility with another event
system.
Configure the $exceptionHandler service used for framework and application errors.
$exceptionHandlerProvider configures the function used by $exceptionHandler.
The default handler rethrows the exception, and custom handlers should preserve
that behavior after reporting the error.
Configure trusted resource URL policies and URL sanitization for SCE.
Use $sceDelegateProvider to control which resource URLs AngularTS may load for
contexts such as templates, includes, iframes, and other resource fetches. It
also owns the URL allowlists used when sanitizing bound link and media URLs.
If the ngSanitize module is included, $sceDelegate will use $sanitize to
clean untrusted HTML automatically.
AngularTS’ default $sceDelegate allows loading from your app’s domain,
blocking others unless explicitly whitelisted.
This small overhead provides major security benefits and simplifies auditing.
Supported Trusted Contexts
Context
Description
$sce.HTML
Safe HTML (used by ng-bind-html).
$sce.CSS
Safe CSS. Currently unused.
$sce.MEDIA_URL
Safe media URLs (auto-sanitized).
$sce.URL
Safe navigable URLs.
$sce.RESOURCE_URL
Safe resource URLs (used in ng-include, iframe, etc.).
$sce.JS
Safe JavaScript for execution.
⚠️ Before AngularTS 1.7.0, a[href] and img[src] sanitized directly. As of 1.7.0, these now use $sce.URL and $sce.MEDIA_URL respectively.
Resource URL List Patterns
Trusted and banned resource URL lists accept:
'self' → matches same domain & protocol
Strings with wildcards:
* → matches within a single path segment
** → matches across path segments (use carefully)
Regular expressions (RegExp)
Caution: Regex patterns are powerful but harder to maintain — use only
when necessary.
Disabling SCE (Not Recommended)
You can disable SCE globally — though this is strongly discouraged.
angular.module('myAppWithSceDisabled',[]).config(function($sceProvider){// Completely disable SCE. For demonstration purposes only!
// Do not use in new projects or libraries.
$sceProvider.enabled(false);});
5.15 - $templateCacheProvider
Configure the cache backing the $templateCache service.
$templateCacheProvider initializes the cache used by $templateCache. The
default cache is a Map, but applications can provide another implementation
that satisfies the TemplateCache contract.
$anchorScroll service scrolls to the element hash or (if omitter) to the current value of $location.getHash(), according to the rules speciffied in the HTML spec.
It also watches the URL hash and automatically scrolls to any matched anchor whenever it is changed by $location. This can be disabled by a setting on $anchorScrollProvider.
Additionally, you can use the yOffset property to specify a vertical scroll-offset (either fixed or dynamic).
Example
<style>#scrollArea{height:100px;overflow:auto;}#bottom{display:block;margin-top:2000px;}</style><sectionng-app="demo"><divid="scrollArea"ng-controller="ScrollController"><buttonclass="bottom"ng-click="gotoBottom()">Go to bottom</button><aid="bottom"></a> You're at the bottom!
</div></section>
window.angular.module('demo',[]).controller('ScrollController',['$scope','$location','$anchorScroll',function($scope,$location,$anchorScroll){$scope.gotoBottom=function(){// set the location.hash to the id of
// the element you wish to scroll to.
$location.setHash('bottom');// call $anchorScroll()
$anchorScroll();};},]);
Demo
You're at the bottom!
The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
Example
<style>.demo2{height:100px;overflow:auto;}.anchor{border:2pxdashedDarkOrchid;padding:10px10px400px10px;}.fixed-header{background-color:rgba(0,0,0,0.2);height:50px;}.fixed-header>a{display:inline-block;margin:5px15px;}</style><sectionid="demo2"class="demo2"><divng-controller="headerCtrl"class="fixed-header"><buttonclass="btn"ng-click="gotoAnchor(x)"ng-repeat="x in [1,2,3,4,5]"> Go to anchor {{x}}
</button></div><divid="anchor{{x}}"class="anchor"ng-repeat="x in [1,2,3,4,5]"> Anchor {{x}} of 5
</div></section>
window.angular.module('demo2',[]).run(['$anchorScroll',function($anchorScroll){$anchorScroll.yOffset=100;// always scroll by 50 extra pixels
},]).controller('headerCtrl',['$anchorScroll','$location','$scope',function($anchorScroll,$location,$scope){$scope.gotoAnchor=function(x){window.$locationTest=$location;constnewHash='anchor'+x;if($location.getHash()!==newHash){// set the $location.hash to `newHash` and
// $anchorScroll will automatically scroll to it
$location.setHash('anchor'+x);}else{// call $anchorScroll() explicitly,
// since $location.hash hasn't changed
$anchorScroll();}};},]);window.angular.bootstrap(document.getElementById('demo2'),['demo2']);
Cookie behavior can be customized globally using
$cookieProvider.defaults.
Cookies are limited to roughly 4 KB, including key and value, so void storing
large objects; prefer identifiers or short tokens.
$eventBus allows communication between an
Angular application instance and the outside context, which can be a different
module, a non-Angular application, a third-party party library, or even a WASM
application. Additionally, $eventBus can be used to communicate directly with
a template, using ng-channel directive.
$eventBus should not be used for communicating between Angular’s own
primitives.
For sharing application state: use custom Services and Factories that
encapsulate your business logic and manage your model.
For intercomponent communication: use $scope.$on(), $scope.$emit(),
and $scope.$broadcast() methods.
The example below demonstrates communication between the global window context
and a controller. Note: Ensure topic clean-up after the $scope is
destroyed
Example
<sectionng-app="demo"><divng-controller="DemoCtrl as $ctrl"> Milliseconds elapsed since the epoch <b>{{ $ctrl.ms }}</b></div></section><!--We are using a regular onclick and `angular` global --><buttonclass="btn btn-dark"onclick="angular.$eventBus.publish('demo', Date.now())"> Publish time
</button>
window.angular.module('demo',[]).controller('DemoCtrl',class{static$inject=['$eventBus','$scope'];constructor($eventBus,$scope){constunsubscribe=$eventBus.subscribe('demo',(val)=>{// `this.ms = val` will not work because `this` is not a proxy
// to trigger change detection, we access controller as a scope property
$scope.$ctrl.ms=val;});$scope.$on('$destroy',unsubscribe);}},);
Demo
Milliseconds elapsed since the epoch {{ $ctrl.ms }}
$exceptionHandler is the central hook for uncaught exceptions inside an AngularTS application.
The framework routes all errors from synchronous code, async tasks, expression evaluation, and dependency injection through this service.
By default, it rethrows exceptions that occur during AngularTS-managed execution. This fail-fast behavior ensures errors are visible immediately in development and in unit tests.
IMPORTANT: In AngularJS, $exceptionHandler only caught errors in expressions and
logged them to the console, using a type signature of $exceptionHandler(exception, [cause]).
AngularTS treats $exceptionHandler as a single error sink, fails eagerly, and assumes that the Error object or one of its subclasses provides all the context necessary for the client.
The $http service is AngularTS’s built-in HTTP client. Use this page for the
behavioral model and common examples. For exact method signatures, parameters,
return types, and interfaces, use the generated TypeDoc reference:
Plain objects are serialized as JSON by the default request transform. File,
Blob, and FormData values are sent as-is so the browser can set the correct
transport headers.
Query parameters are serialized by $httpParamSerializer. Arrays produce
repeated keys, objects are JSON encoded, and null, undefined, and functions
are omitted.
Successful 2xx responses resolve with an HttpResponse<T>. Non-2xx responses,
timeouts, aborts, and network errors reject with the same response shape, so
error handlers can inspect status, statusText, headers, config, and
xhrStatus.
$http.get<User>('/api/users/99').catch((error)=>{if(error.xhrStatus==='timeout'){message='Request timed out.';}elseif(error.status===404){message='User not found.';}});
Defaults
Configure defaults before bootstrap with $httpProvider.defaults, or mutate
runtime defaults through $http.defaults.
Normalize and update browser URLs across HTML5 and hashbang modes.
$location parses the browser URL into path, search, hash, and state pieces.
Changes made through $location update the browser address bar, and browser
navigation updates the service.
Setter methods return $location, so updates can be chained.
Navigation Events
$locationChangeStart is broadcast on $rootScope before the URL changes. Call
event.preventDefault() from a listener to cancel the navigation.
$locationChangeSuccess is broadcast after the URL changes. In HTML5 mode,
listeners may also receive the new and old history state values when the browser
supports the History API.
Default implementation of
LogService safely writes the
message into the browser’s
console (if
present). The main purpose of this service is to simplify debugging and
troubleshooting, while allowing the developer to modify the defaults for live
environments.
Note: Not all browsers support blackboxing. The default is to log debug messages. You can use
$logProvider.debug
to change this.
For configuration and custom implementations, see
$logProvider.
Decorating $log
You can also optionally override any of the $log service methods with
$provide decorator. Below is a simple example that overrides default
$log.error to log errors to both console and a backend endpoint.
If your application is already heavily reliant on default
console logging or
you are using a third-party library where logging cannot be overriden, you can
still take advantage of Angular’s services by modifying the globals at runtime.
Below is an example that overrides default console.error to logs errors to
both console and a backend endpoint.
Example*
angular.module('demo').run(($http)=>{/**
* Decorate console.error to log error messages to the server.
*/const$delegate=window.console.error;window.console.error=(...args)=>{try{consterrorMessage=args.map((arg)=>(arginstanceofError?arg.stack:JSON.stringify(arg))).join(' ');$delegate.apply(console,args);$http.post('/api/log/error',{message:errorMessage});}catch(e){console.warn(e);}};/**
* Detect errors thrown outside Angular and report them to the server.
*/window.addEventListener('error',(e)=>{window.console.error(e.error||e.message,e);});/**
* Optionally: Capture unhandled promise rejections
*/window.addEventListener('unhandledrejection',(e)=>{window.console.error(e.reason||e);});});
Combining both $log decoration and console.log overriding provides a robust
and flexible error reporting strategy that can adapt to your use-case.
* array notation and HTTP error handling omitted for brevity
6.11 - $machine
Reactive mode machines with declarative transitions
$machine
$machine creates a small reactive mode machine for UI and application flows.
It is more than a regular service or factory because the returned machine is
designed to be wrapped by AngularTS scope proxies: current and data update
templates naturally, and send() batches transition work when a scope proxy is
observing the machine.
Use ordinary services for IO, persistence, and shared domain logic. Use
$machine when the important part is the allowed flow between modes.
Use $workflow when the flow also
needs command boundaries, diagnostics, snapshots, restore, retry, or repeat.
Create a Machine
Inject $machine and assign the created machine to a controller or scope
property:
This is useful when defaults depend on environment, user state, or persisted
configuration.
Named machines are regular DI services. The injector creates one machine
instance and reuses it for that injectable name.
Template API
The machine exposes a small template-friendly API:
<buttonng-disabled="!$ctrl.session.matches('setup')">Random</button><divng-show="$ctrl.session.matches('waiting')">Waiting for opponent...</div><span>{{ $ctrl.session.data.roomId }}</span>
Runtime API
session.current;// current mode string
session.data;// reactive data object
session.matches('setup');// true when current mode is setup
session.can('join',payload);// true when current mode can run join
session.send('join',payload);session.snapshot();// structured clone of { current, data }
session.restore(snapshot);
send(type, payload) returns true when a transition entry exists for the
current mode, its optional guard passes, and its handler runs. Missing
transitions and blocked guarded transitions return false and do not throw.
$machine does not record diagnostics for blocked or missing transitions; use
$workflow when failures need structured evidence, retry, or recovery.
Transition return values:
return a mode string to change current
return false, undefined, an empty string, a non-string value, or no value
to stay in the current mode
can(type, payload) checks the transition table and any optional guard for the
current mode. It does not run the transition target. Guards should be
side-effect-free because templates may call can() repeatedly.
Guarded Transitions
Use a transition descriptor when a transition has a cheap synchronous condition
that templates or controllers should be able to ask about through can():
constsession=$machine({initial:'setup',data:{roomId:'',inviteCode:'',},transitions:{setup:{join:{guard(data,message){return!!data.inviteCode&&message.roomId!=='';},target(data,message){data.roomId=message.roomId;return'waiting';},},},},});session.can('join',{roomId:'abc'});// evaluates guard only
session.send('join',{roomId:'abc'});// runs target when guard passes
Guards and transitions are synchronous. Put async work, retries, diagnostics,
and command recovery in $workflow,
then use a machine transition to project the resulting mode/data into the UI.
Example: Tic Tac Toe
A machine is useful when user actions must follow a small set of legal modes.
This example keeps a tic tac toe game in playing until a move produces a win
or draw. Once the machine reaches xWon, oWon, or draw, there is no move
transition for that mode, so further moves return false.
The transition owns both validation and projection. A valid move mutates
data.board, updates whose turn is next, and returns the next mode. An invalid
move records lastError and returns false, leaving current unchanged.
Machine transitions do not roll back data mutations when they return false or
throw.
Persist With Transition Hooks
Transition hooks are a convenient place to persist the game after each handled
move. The hook runs after current has been updated, so the snapshot contains
the terminal mode when the move ends the game.
app.controller('GameCtrl',function($machine){conststorageKey='tic-tac-toe';this.game=$machine({initial:'playing',data:{board:['-','-','-','-','-','-','-','-','-'],nextPlayer:'X',winner:'',moveCount:0,lastError:'',},transitions:{playing:{move(data,{index}){// Same move logic as above.
},},},hooks:{transition({machine}){localStorage.setItem(storageKey,JSON.stringify(machine.snapshot()));},},});constsaved=localStorage.getItem(storageKey);if(saved){this.game.restore(JSON.parse(saved));}});
restore() does not run hooks, so loading the saved game will not immediately
write another snapshot. The next successful send() call will persist the
updated machine state.
Snapshots
Use snapshot() to capture the durable machine state. A snapshot is a
structured clone of { current, data }:
A snapshot contains only current and data. It has no version or machine id,
and it does not include transitions or hooks; those still come from the machine
config. Use $workflow or a workflow supervisor when persisted recovery needs
versioning, diagnostics, history, retry, or migration.
The clone uses the browser’s structuredClone() behavior. Values such as
objects, arrays, Dates, Maps, Sets, typed arrays, and cycles can be cloned.
Functions, DOM nodes, and other non-cloneable values will throw the native
structured clone error.
JSON persistence is a narrower contract. Use JSON.stringify(snapshot) only
when data is JSON-compatible, or add your own encode/decode layer before
storing the snapshot.
Use restore(snapshot) to recover an existing machine:
restore() mutates the existing data object in place so scope proxies and
templates keep their identity. Keys missing from the snapshot are removed,
nested plain objects are merged in place, and non-plain values like arrays are
replaced with cloned snapshot values. Restore does not run transition hooks.
Hooks
Use hooks.enter and hooks.exit for mode-specific effects. Use
hooks.transition for logging or cross-cutting work that should run after any
handled transition, including same-mode transitions:
Hook context contains type, from, to, payload, data, and machine.
exit runs before current changes, enter runs after current changes, and
transition runs after mode-specific hooks. Missing transitions do not run
hooks.
Hooks run synchronously inside the same send() batch. A hook may call
machine.send() to run another valid transition; nested sends are batched with
the outer transition. If a transition or hook throws, the error is rethrown,
prior data/current mutations are kept, and AngularTS still schedules bound
scopes for the keys touched by the attempted transition.
Scope Ownership
$machine(config) does not tie the machine to the lifetime of any one scope.
The machine stores durable mode and data internally. When an AngularTS scope
proxy wraps the machine, the machine registers with that proxy and uses its
scheduler for reactive template updates and batched send() calls.
That means a machine can be created once, assigned to a component, survive that
component being destroyed, and later be assigned to another scope.
An explicit $machine($scope, config) call is also supported when a caller
wants to bind the machine to a scope immediately, but assigning the machine to a
controller or scope property is usually enough. Named machines registered with
module.machine() follow the same rule: they bind when a scope proxy observes
them.
Machine definitions are strict by default in TypeScript. If no event map is
provided, send() has no valid event names and transition maps accept no event
keys. Use defineMachine<Data, Events>() for checked event names and payloads,
or opt into ng.MachineEventMap when you intentionally need dynamic event
names.
6.12 - $parse
URL normalization for HTML5/hashbang modes
6.13 - $rest
Typed REST resource client
The $rest service creates typed resource clients on top of a REST backend. Use this
page for the usage model and examples. Exact class members, method signatures,
return types, and configuration interfaces live in TypeDoc:
When an entity class is supplied, response objects are passed through
new entityClass(data) before they are returned.
Request Options
The third factory argument is merged into backend requests. With the default
HTTP backend, use it for headers, credentials, cache options, transforms, or
custom param serialization.
Pass backend when a resource should use a custom backend. The backend receives
a normalized RestRequest with expanded URLs, params, request data, collection
URL, and resource id. This is the extension point for tests, local persistence,
IndexedDB, the browser Cache API, or composed network/cache behavior.
For cached reads, wrap the HTTP backend with CachedRestBackend:
createRestCacheKey() is used internally by CachedRestBackend; it is not part
of the top-level AngularTS namespace. Cache stores receive the final key string
through the RestCacheStore methods and should treat it as opaque.
Request Bodies
When the default HTTP backend is used, request data is serialized by $http.
Scope proxies are deproxied before JSON serialization, so proxy helper
properties such as $target, $handler, and $proxy are not sent to the
server. AngularTS-generated repeat identity is stored in internal metadata, not
on the object, so it is not included in write payloads either.
Explicit application-owned fields are still normal data. If your model defines a
property such as $hashKey, $rest does not remove it.
URI Templates
Resource URLs support RFC 6570 URI templates. Variables wrapped in braces are
expanded from the params passed to methods such as list().
The CRUD demo at /src/services/rest/rest-crud-demo.html talks to the Go demo
backend through /api/tasks. It uses ng-repeat for rows, $rest for CRUD
operations, and a cache strategy toggle for network-first,
cache-first, and stale-while-revalidate.
If the ngSanitize module is included, $sceDelegate will use $sanitize to
clean untrusted HTML automatically.
AngularTS’ default $sceDelegate allows loading from your app’s domain,
blocking others unless explicitly whitelisted.
This small overhead provides major security benefits and simplifies auditing.
Supported Trusted Contexts
Context
Description
$sce.HTML
Safe HTML (used by ng-bind-html).
$sce.CSS
Safe CSS. Currently unused.
$sce.MEDIA_URL
Safe media URLs (auto-sanitized).
$sce.URL
Safe navigable URLs.
$sce.RESOURCE_URL
Safe resource URLs (used in ng-include, iframe, etc.).
$sce.JS
Safe JavaScript for execution.
⚠️ Before AngularTS 1.7.0, a[href] and img[src] sanitized directly. As of 1.7.0, these now use $sce.URL and $sce.MEDIA_URL respectively.
Resource URL List Patterns
Trusted and banned resource URL lists accept:
'self' → matches same domain & protocol
Strings with wildcards:
* → matches within a single path segment
** → matches across path segments (use carefully)
Regular expressions (RegExp)
Caution: Regex patterns are powerful but harder to maintain — use only
when necessary.
Disabling SCE (Not Recommended)
You can disable SCE globally — though this is strongly discouraged.
angular.module('myAppWithSceDisabled',[]).config(function($sceProvider){// Completely disable SCE. For demonstration purposes only!
// Do not use in new projects or libraries.
$sceProvider.enabled(false);});
6.17 - $templateCache
Map object for storing templates
$templateCache is a
Map
object created by $templateCacheProvider.
The first time a template is used, it is loaded in the template cache for quick
retrieval. You can load templates directly into the cache in a script tag by
using $templateRequest or by consuming the $templateCache service directly.
Note: the script tag containing the template does not need to be included in the
head of the document, but it must be a descendent of the $rootElement (e.g.
element with ng-app attribute), otherwise the template will be ignored.
Adding via the $templateCache service:
Example
constmyApp=angular.module('myApp',[]).run(($templateCache)=>{$templateCache.set('templateId.html','This is the content of the template');});
To retrieve the template, simply use it in your component:
Inspectable command workflows built on reactive mode machines
$workflow
$workflow adds command boundaries, diagnostics, history, snapshots, restore,
retry, and repeat on top of $machine.
Use $machine when you only need legal modes and transitions. Use $workflow
when external work needs to be run, inspected, repaired, repeated, or handed to
another process as JSON.
Create a Workflow
Inject $workflow and assign the workflow to a controller or scope property:
workflow.current is the current mode. workflow.data is reactive data for
templates. workflow.run(name, input) is the explicit boundary for work that
can succeed, fail, or be retried.
Commands may be synchronous or async. run(), retry(), and repeat() always
return a promise that resolves to a normalized WorkflowCommandResult.
Register a Named Workflow
Use module.workflow(name, config) when a workflow should be injectable by
name:
Named workflows are DI singletons for an injector. Observing scopes can be
destroyed without destroying the workflow instance.
Command Diagnostics
Commands return a WorkflowCommandResult, or they can throw. Thrown values are
converted to structured diagnostics and partial data mutations are preserved:
restore(snapshot) requires version 1 and a matching workflow id. Restored
diagnostics and history entries are normalized into the same JSON-safe shape
that live commands produce. Restored history IDs are normalized to unique
positive integers. Command inputs and outputs in workflow.history and
snapshots are stored as JSON-safe projections. Live workflows still retry or
repeat with the original input value; after restore(snapshot), retry and
repeat use the serialized input from the snapshot.
Use migrateSnapshot(snapshot) to restore older persisted shapes:
Diagnostics and history are append-only in v1. Repair, retry, and repeat add
evidence; they do not erase the commands that made recovery or replay necessary.
Production Policies
Concurrent command calls are allowed by default. Set concurrency to reject or
queue overlapping runs for the same command:
Use commandTimeout or per-run timeout to fail commands that exceed a time
budget. Timeout and cancellation resolve the command result with diagnostics;
commands receive an AbortSignal so async work can stop early:
cleanup(callback) runs after the command resolves, fails, times out, or is
cancelled. Use it for timers, event listeners, observers, and request
controllers created by the command.
restore(snapshot) is a hard recovery boundary. It cancels running commands,
prevents queued commands from starting, and ignores late writes from cancelled
command continuations. Command code should still observe signal.aborted so it
can release external resources promptly.
Diagnostics and history are bounded to 1000 entries by default. Use
diagnosticLimit and historyLimit to choose different bounds:
Workflow definitions are strict by default in TypeScript. If no event or command
map is provided, send(), run(), retry(), and repeat() have no valid
names. Use defineWorkflow<Data, Events, Commands>() and defineCommand() for
checked event names, command names, inputs, and outputs:
When a command map is provided, commands is required and every declared
command key must be present and callable. This keeps workflow.run('name')
aligned with the runtime command table.
When a command calls another command, pass the full command map to
defineCommand() so context.workflow.run() is checked too:
Use ng.WorkflowCommandMap only when you intentionally need dynamic command
names. Dynamic command inputs are typed as unknown; narrow the value inside
the command before using it.
7 - Service Guides
7.1 - Making HTTP requests with the $http service
Send requests with the $http service and configure defaults, transforms, interceptors, and XSRF behavior.
Use $http for application HTTP calls when you need request configuration,
response transforms, interceptors, or integration with AngularTS services.
This guide focuses on workflows. Exact call signatures and exported interfaces
live in TypeDoc:
Rejected requests use the same response object shape as successful requests.
Use status for HTTP errors and xhrStatus for transport outcomes such as
timeouts and aborts.
$http.get<User>('/api/users/99').catch((error)=>{if(error.xhrStatus==='timeout'){this.error='Request timed out.';}elseif(error.status===404){this.error='User not found.';}elseif(error.status===0){this.error='Network error.';}});
XSRF
$http can read a configured XSRF cookie and send it in a configured request
header. Cross-origin APIs must be listed as trusted origins before AngularTS
sends the token to them.
subscribe() returns an unsubscribe function. Keep that function and call it during teardown, especially from long-lived services, directive controllers, or manually bootstrapped integrations.
One-time listeners
Use subscribeOnce() for initialization handshakes where only the first event matters.
This makes $eventBus useful for browser callbacks, WebSocket messages, Web Worker results, and other boundaries where you want the publisher to stay independent of Angular controller timing. When a subscriber changes view state, write through proxied scope or controller state so AngularTS can observe the assignment.
Error handling
If a subscriber throws, $eventBus forwards the error to $exceptionHandler and continues delivering the event to the remaining subscribers.
Publisher and subscriber do not share a scope ancestry
Yes
No
Event comes from non-Angular code
Yes
No
Communication is strictly parent/child
Usually no
Yes
Delivery should be async
Yes
No
Listener cleanup should be tied to a scope
Works with $destroy
Built for it
Use $eventBus for cross-boundary messages such as WebSocket events, global notifications, analytics readiness, and application-level domain events. Use scope events for local component coordination.
EventSource does not support arbitrary custom headers in browsers. For authenticated streams, use cookies with withCredentials or include a short-lived token in query params.
WebSockets
$websocket returns a managed WebSocket connection with reconnects, heartbeat handling, message transforms, and send support.
send() serializes values as JSON before passing them to the native WebSocket.
WebTransport
$webTransport opens a browser-native WebTransport session. Use it when an
endpoint can serve HTTP/3 and the client benefits from unreliable datagrams,
reliable streams, or both in the same session.
The service expects the browser WebTransport API to exist and requires an
https: URL with an explicit port. The test backend exposes certificate hash
metadata at /webtransport/cert-hash for local browser tests.
Reconnect is opt-in at the service layer. When enabled, the
WebTransportConnection object stays stable while its native transport
instance is replaced. Use onReconnect as the renegotiation hook for
subscriptions, authentication messages, or other session state that the server
does not remember across HTTP/3 sessions.
For template-level feeds, ng-web-transport connects on load by default and
evaluates lifecycle expressions. data-mode="datagram" is the default;
data-mode="stream" reads server-opened unidirectional streams.
data-transform accepts bytes, text, or json. Message expressions receive
$connection, $data, $message, $event, and $text for text/json modes.
Reconnect is opt-in with data-reconnect="true"; tune it with
data-retry-delay and data-max-retries. data-on-reconnect runs after the
replacement session is ready and receives $attempt, $connection, $error,
and $url.
Web Workers
Use ng-worker when a view action should run CPU-heavy JavaScript outside the main thread.
The directive evaluates data-params, posts the result to the worker, and exposes worker responses as $result in data-on-result. When no result expression is provided, it swaps the result into the element using the configured swap strategy.
A worker module receives values through self.onmessage and returns results through self.postMessage.
Define typed REST endpoints once and use $rest for list, get, create, update, and delete flows backed by pluggable backends.
$rest wraps a REST backend with a small typed resource client. By default it uses $http; pass a custom backend when a resource should read from another data source or compose network and cache behavior.
Register shared resources in a config block. The provider stores resource definitions before the application starts, then the $rest factory uses the live $http service at runtime.
Params that are not consumed by the template are forwarded to $http as query params.
Map server data to classes
Pass an entity class when the raw response needs normalization, computed properties, or methods.
classArticle{id: number;title: string;publishedAt: Date;constructor(data: any){this.id=data.id;this.title=data.title;this.publishedAt=newDate(data.published_at);}getisPublished() {returnthis.publishedAt.getTime()<=Date.now();}}constarticles=$rest<Article,number>("/api/articles",Article);constarticle=awaitarticles.get(42);if(article?.isPublished){// article is a real Article instance.
}
If you omit the entity class, $rest returns the parsed response data as-is.
Handle writes
create() sends POST, update() sends PUT, and delete() sends DELETE. The methods intentionally stay close to HTTP semantics so errors and interceptors still flow through $http.
$rest does not perform framework-property cleanup itself. With the default
HTTP backend, $http deproxies scope payloads before JSON serialization, so
proxy helpers such as $target, $handler, and $proxy do not reach the
server. Generated repeat identity is stored as internal metadata rather than on
your model object, so it is not included in request bodies. Explicit
application-owned properties remain part of the payload.
Use a cached backend
CachedRestBackend wraps a network backend and an async cache store. The default HTTP backend remains available through HttpRestBackend, while cache storage can be memory, IndexedDB, the Cache API, or any object that implements RestCacheStore.
Supported read strategies are cache-first, network-first, and stale-while-revalidate. Writes always go to the network backend first; successful writes invalidate cached collection and entity keys for the resource.
Cache keys are generated by CachedRestBackend. A RestCacheStore receives the
final key string in get(), set(), delete(), and deletePrefix() and should
treat that key as opaque. createRestCacheKey() is an internal REST module
helper, not a top-level namespace API.
Write a custom backend
A custom backend implements RestBackend. It receives normalized requests and
returns raw response data for RestService to map.
Use HttpRestBackend when the backend should delegate to $http, and wrap it
with CachedRestBackend when reads should use one of the cache strategies.
CRUD demo
The demo at /src/services/rest/rest-crud-demo.html uses the Go demo backend
through /api/tasks. It shows list(), get(), create(), update(), and
delete() against a real HTTP endpoint, renders rows with ng-repeat, and
includes a cache strategy toggle for network-first, cache-first, and
stale-while-revalidate.
Navigate between named states, read and modify the URL, manage history, and intercept route transitions.
AngularTS has two routing layers. $location manages the browser URL and history directly. $state works at the application level with named states, parameters, resolves, and transition hooks.
go() returns a transition promise. Use transition options when you need to control reloads, parameter inheritance, URL updates, or relative navigation.
Generate Links
Use $state.href() when templates or controllers need a URL without starting navigation.
Read and write cookies with $cookie, serialize objects, and use $window.localStorage or sessionStorage for client-side persistence.
AngularTS provides $cookie for typed, injectable cookie access and $window for direct browser storage access. Prefer injected services over globals so unit tests can replace browser APIs without patching window or document.
A cookie can only be removed when the path and domain used for removal match the values used when it was created. If a cookie was created with path: "/", pass the same path when removing it.
Provider Defaults
Set defaults once when every cookie should share the same attributes.
8.1 - State-based routing in AngularTS applications
Learn how AngularTS implements state-based routing with states, views, resolves, transitions, and URL matching configured via $stateProvider.
AngularTS ships a full-featured router ported from UI-Router. Unlike simple URL-based routers, it models your application as a state machine: each screen or workflow step is a named state, and navigation means transitioning from one state to another. URLs are one way to enter a state, but they are not the primary concept—states are.
Key concepts
The router is built from five interlocking primitives:
States — named nodes in the application state tree. Each state can have a URL, template, controller, and resolved data.
Views — the rendered output of a state, inserted into a ng-view element in the DOM.
Resolves — asynchronous data-fetching functions that run before a state is entered.
Transitions — the lifecycle of moving from one state (or set of states) to another, with hooks you can intercept.
URL matching — an optional layer that maps browser URLs onto states and keeps them in sync.
How routing integrates with the module system
The router exposes three injectable services that cover the full routing API:
Token
Type
Purpose
$state
StateProvider
Navigate (go, transitionTo), inspect current state (is, includes, current)
Register and deregister state declarations at runtime
All three share a RouterProvider globals object that tracks the current StateObject, the active Transition, and the latest resolved StateParams. The RouterProvider is injected as $router and holds $router.current, $router.transition, and $router.params.
Setting up the router
Register your states during config
Call $stateProvider.state(declaration) inside an Angular config block, or use
the equivalent module-level module.state(declaration) convenience. States must
have a unique name.
Place ng-view where you want the active state’s template to render. An unnamed ng-view receives the default view.
<!DOCTYPE html><htmlng-app="app"><body><nav><ang-sref="home"ng-sref-active="active">Home</a><ang-sref="contacts"ng-sref-active="active">Contacts</a></nav><!-- Active state template renders here --><divng-view></div></body></html>
Navigate between states
Use $state.go() in controllers or services to perform programmatic navigation.
ng-view is a viewport directive that renders the template and controller for the currently active state. When a transition completes, the view is swapped in. Multiple named views can coexist:
<divng-view></div><!-- Named views --><divng-view="header"></div><divng-view="content"></div><divng-view="sidebar"></div>
A state targets named views through its views property:
The ng-view directive emits $viewContentLoading before the DOM is rendered and $viewContentLoaded after. It also supports autoscroll and onload attributes.
Router directives
ng-sref
ng-sref generates an href for a state and triggers $state.go() on click. The value is a state name optionally followed by a params object:
<ang-sref="home">Home</a><!-- With parameters --><ang-sref="contacts.detail({ contactId: contact.id })">{{ contact.name }}</a><!-- Relative navigation --><ang-sref="^">Up to parent</a><ang-sref=".child">Down to child</a>
The ng-sref-opts attribute passes TransitionOptions:
Dashboard
</a>
ng-sref-active
ng-sref-active adds a CSS class when the linked state (or any of its descendants) is active:
Fetch data asynchronously before a state is entered, with eager and lazy policies.
8.2 - States
Define state hierarchies, resolve data, register states, and navigate with $state.
A state represents a place in an AngularTS application: a page, a nested layout,
a modal, or a step in a workflow. States are declared as plain objects and
registered through $stateProvider during configuration or $stateRegistry at
runtime.
Register most states in a config block, or use module.state() for the same
provider registration through the fluent module API. Calls to both
$stateProvider.state() and module.state() are chainable.
Use $state.go() for normal application navigation. It supports absolute
states, parent-relative states, sibling-relative states, params, and transition
options.
Understand the AngularTS transition lifecycle and use hooks like onBefore, onStart, onSuccess, and onError for auth guards, analytics, and redirects.
Every navigation in AngularTS is a Transition—a structured object that describes moving from one state (or set of states) to another. Transitions carry the from-state, the to-state, all parameter values, the tree of entering/exiting/retained states, and the resolve context. You hook into their lifecycle to implement auth guards, loading indicators, analytics, scroll resets, and more.
What is a transition
When you call $state.go('contacts.detail', { contactId: 42 }), the router creates a Transition instance. Internally it computes a TreeChanges object with five paths:
Path
Description
from
All currently active nodes, from root to the current leaf state
to
All nodes that will be active after the transition
exiting
Nodes that are active now but will not be active after (in reverse order, deepest first)
retained
Nodes that are active both before and after (unchanged)
entering
Nodes that are not active now but will be active after (parent first)
The Transition exposes these paths through trans.exiting(), trans.retained(), and trans.entering(), each returning an array of StateDeclaration objects. Use trans.treeChanges(pathname) for the raw PathNode[] arrays.
Each transition has a numeric $id and a promise that resolves to the StateDeclaration for the to-state on success, or rejects with a Rejection on failure.
Transition lifecycle
The router runs hooks in a fixed sequence of phases:
onCreate (synchronous)
Fires during transition construction before the transition is returned. Used internally for view config setup and global state updates. Not available for application hooks.
onBefore (synchronous)
Fires before any state is exited or entered. This is the right place for synchronous guards that should prevent the transition from even starting.
onStart (async)
Fires as the transition starts running—after onBefore is settled but before any states are exited. Eager resolves are fetched here.
onExit (async, deepest first)
Fires for each state being exited, starting with the deepest and moving toward the root.
onRetain (async)
Fires for each state that is being retained (neither entered nor exited).
onEnter (async, shallowest first)
Fires for each state being entered, starting with the parent and moving toward the leaf. Lazy resolves for entering states are fetched before each state’s onEnter.
onFinish (async)
Fires after all onEnter hooks are done. This is the last chance to cancel or redirect before the transition is committed.
onSuccess / onError (synchronous, after commit)
Fires after the transition is fully committed. onSuccess hooks run when the promise resolves; onError hooks run when it rejects. Return values are ignored at this stage.
Registering hooks
All hook registration methods are on the $transitions service (injected as $transitions or ng.TransitionService). Each method returns a deregistration function.
$transitions.onBefore(matchCriteria: HookMatchCriteria,callback:(transition: Transition)=>HookResult,options?: HookRegOptions):()=>void// deregister function
Hook match criteria
HookMatchCriteria is an object with optional keys to, from, exiting, retained, and entering. Each value is:
A state name string or glob ('contacts.**')
A function(state, transition) => boolean
true to match any state (the default when the key is omitted)
$transitions.onStart({},callback);// Matches transitions going to any child of 'admin'
$transitions.onBefore({to:'admin.**'},callback);// Matches transitions where a specific state is being exited
$transitions.onExit({exiting:'contacts.detail'},callback);// Matches using a function predicate
$transitions.onStart({to:function(state){returnstate.data!=null&&state.data.requiresAuth===true;}},callback);
Hook registration options
priority:10,// higher priority runs first (default: 0)
bind:myObject,// `this` inside callback
invokeLimit:1// auto-deregister after N invocations
});
Hook return values (HookResult)
The return value of a hook controls the transition:
Return value
Effect
undefined / anything else
Transition continues normally
false
Transition is cancelled (aborted)
TargetState
Transition is redirected to the new target
Promise<false>
Transition waits for the promise; cancels if it resolves to false
Promise<TargetState>
Transition waits for the promise; redirects when it resolves
Rejected Promise
Transition fails with the rejection reason
Note:onSuccess and onError hooks run after the transition is committed. Their return values are ignored—you cannot cancel or redirect from these hooks.
Redirecting from a hook
Return a TargetState created with $state.target():
// Always redirect 'home' to 'home.dashboard' as a default substate
return$state.target('home.dashboard');});
The router internally creates a new transition to the redirect target and chains the promises. If the original transition was triggered by a URL change, the redirect uses location: 'replace' so the original URL is removed from history.
Cancelling a transition
Return false from any hook that runs before onSuccess:
if(appIsLocked){returnfalse;// abort
}});
A cancelled transition is rejected with a Rejection of type ABORTED. The browser URL is reset to the previous location by the built-in updateUrl hook.
Common hook patterns
Authentication guard
This pattern intercepts any transition to a state with data.requiresAuth and redirects unauthenticated users to the login page.
.run(function($transitions,$state,AuthService){$transitions.onBefore({to:function(state){returnstate.data&&state.data.requiresAuth;}},function(transition){if(!AuthService.isAuthenticated()){// Redirect to login, passing the intended destination
return$state.target('login',{redirectTo:transition.to().name});}});});
varAuthService=transition.injector().get('AuthService');if(!AuthService.isAuthenticated()){// Return a promise; transition waits for it to settle
returnAuthService.authenticate().catch(function(){return$state.target('guest');});}});
Transition results
A transition can finish in one of four states:
Result
Description
Success
All hooks passed, the to-state is now active. transition.success === true.
Error
A hook threw, returned a rejected promise, or a resolve failed. transition.success === false, transition.error() contains the reason.
Ignored
The transition targets the same state with the same parameters that are currently active. Treated as success from the transitionTo() perspective.
Superseded
A newer transition started before this one finished. The older transition is abandoned; the newer one continues.
Redirected transitions are not an error from the caller’s perspective: $state.go() transparently chains to the redirect target’s promise.
Accessing the transition object
The active transition is stored on $router.transition. Inside any hook, the Transition instance is passed as the first argument.
transition.redirectedFrom() returns the previous transition in a redirect chain. transition.originalTransition() walks the entire chain back to the first transition.
Per-transition hooks
Hooks can also be registered on a specific Transition instance rather than globally on $transitions. These hooks only affect that single transition:
trans.onSuccess({},function(){console.log('This specific transition succeeded.');});
Warning: Per-transition hooks must be registered before the transition has finished running. Register them synchronously in the same call stack as the navigation, or in an onStart global hook.
Dynamic resolvables in hooks
An onBefore hook can add additional resolve data to the current transition using transition.addResolvable(). The added resolvable is available to hooks and views that run after it:
Within a phase (e.g., all onStart hooks), hooks are invoked in descending priority order. The default priority is 0. Built-in hooks like URL update and view activation use priorities in the range 9000–10000, so application hooks with the default priority run before them.
For onExit, hooks are invoked deepest-first (children before parents). For onEnter, hooks are invoked shallowest-first (parents before children). This ordering is fixed regardless of priority.
8.4 - URL matching and configuration in AngularTS router
Configure URL parameters, typed path and query params, hash vs HTML5 mode, base href, and custom parameter types in the AngularTS state-based router.
The AngularTS router matches the browser’s URL against registered state declarations and activates the best matching state. URL matching is an optional layer on top of the state machine—states can be navigated to programmatically without any URL involvement—but most applications use URLs to make deep-linking and browser history work correctly.
How URL matching works
When the browser URL changes (or on initial load), the UrlService calls sync(). It iterates all registered URL rules in priority order and finds the best match using a weighted scoring system. The winning rule’s handler is called, which calls $state.go() with the matched state and extracted parameter values.
URL rules are created automatically for every state that has a url property. You can also register custom URL rules directly on $urlService._rules.
UrlService.match(url) accepts a UrlParts object ({ path, search, hash }) and returns a MatchResult with the matching rule, the match data, and the match weight. Rules with the same sort order are ranked by weight so the most specific match wins.
URL parameters
Parameters are declared in the state’s url string. The router uses a UrlMatcher compiled from this pattern to test URLs and extract values.
Give a parameter a default value in the params block and set squash: true to make it optional. When the URL is visited without the parameter, the default value is used. When navigating with the default value, the parameter is omitted from the URL:
name:'userList',url:'/users/:page',params:{page:{value:'1',// default value
squash:true// remove from URL when value equals default
}},component:'UserList'});// /users/ → { page: '1' } (squashed)
// /users/3 → { page: '3' }
Built-in parameter types
The UrlConfigProvider ships the following built-in parameter types. Specify the type inline in the URL pattern or in the params block:
string
Default for path parameters. Encodes and decodes as a plain string. Slashes within the value are encoded as ~2F in AngularTS’s patched path type to avoid ambiguity in Angular 1’s $location.
Encodes Date objects as YYYY-MM-DD strings. Parses the string back to a Date on the way in.
url:'/events?{startDate:date}&{endDate:date}'// { startDate: new Date('2024-01-15') }
// → /events?startDate=2024-01-15
hash
The internal parameter type used for the # (hash/anchor) portion of the URL. Has inherit: false so the hash is not carried forward to child state transitions.
URL configuration with UrlConfigProvider
UrlConfigProvider (injected as $urlConfigProvider in config blocks, or accessed via $url._config at runtime) controls global URL matching behavior.
Case sensitivity
URL matching is case-sensitive by default. Allow case-insensitive matching:
Control the global default for how parameters with default values appear in URLs:
.config(function($urlConfigProvider){// 'false' (default): include the default value in the URL
// 'true': omit default value from URL
// '~': replace default value with '~' in the URL
$urlConfigProvider.defaultSquashPolicy(true);});
Custom parameter types
Register a custom ParamType before using it in state URL patterns. The type must implement encode, decode, is, equals, and optionally pattern:
.config(function($urlConfigProvider){// Encodes an array of integers as a dash-separated string
$urlConfigProvider.type('intarray',{encode:function(array){returnarray.join('-');},decode:function(str){returnstr.split('-').map(function(x){returnparseInt(x,10);});},is:function(val){returnArray.isArray(val)&&val.every(function(x){returntypeofx==='number'&&!isNaN(x);});},equals:function(a,b){returna.length===b.length&&a.every(function(x,i){returnx===b[i];});},pattern:/[0-9]+(?:-[0-9]+)*/});});
Note: Register custom types before any state that uses them. UrlConfigProvider.type() returns the provider itself for chaining.
Hash mode vs HTML5 mode
AngularTS inherits Angular 1’s $location modes. Configure the mode on $locationProvider:
Hash mode (default)
URLs use a hash fragment: http://example.com/app/#/contacts/42. No server configuration is needed; the hash segment is never sent to the server.
angular.module('app').config(function($locationProvider){$locationProvider.html5Mode(false);$locationProvider.hashPrefix('!');// optional: use #!/ instead of #/
});
The UrlService.href() method prepends # (plus the hash prefix) when generating hrefs in hash mode.
HTML5 mode (pushState)
URLs use real paths: http://example.com/contacts/42. The server must return the app’s index.html for all routes.
angular.module('app').config(function($locationProvider){$locationProvider.html5Mode({enabled:true,requireBase:true// <base href="..."> must be present in <head>
});});
In HTML5 mode, UrlService.href() prepends the base path (stripped of its last segment) rather than a hash.
Base href
In HTML5 mode, the base href is read from the <base> tag in the document <head>:
<basehref="/myapp/"></head>
UrlService.baseHref() returns the current base href. If no <base> tag is present it falls back to window.location.pathname. The base href is used when constructing absolute URLs via $state.href(..., { absolute: true }) and when pushing new history entries.
varbase=$url.baseHref();// "/myapp/"
Reading the current URL
UrlService provides three methods to read URL components:
$url.getPath();// "/contacts/42"
$url.getSearch();// { tab: 'notes' }
$url.getHash();// "section1"
// All three at once
varparts=$url.parts();// { path: '/contacts/42', search: { tab: 'notes' }, hash: 'section1' }
// The full normalized URL (strips base, adds hash prefix in hash mode)
$url.url();// "/contacts/42?tab=notes#section1"
Updating the URL
UrlService.url(newUrl) replaces the current URL. The router then calls sync() to find and activate the matching state:
$url.url('/contacts/99?tab=history');
UrlService.push() is the internal method used by the built-in onSuccess hook to update the browser address bar after a successful state transition:
When multiple rules could match the same URL, the router scores each match and picks the winner:
Rules are sorted by a primary sort order (rules created from state declarations all share the same group).
Within a group, the match with the highest weight wins. Weight is computed by counting matched segments, typed parameters, and specificity of regexps.
A state URL like /users/{id:int} outweighs /users/:id for the path /users/42 because the typed parameter provides a stricter match.
Exact path matches score higher than prefix matches. Query parameters do not affect path scoring but must all be present if declared without defaults.
Listening for URL changes
UrlService.onChange(callback) registers a low-level listener that fires on every $locationChangeSuccess event. The listener receives the Angular scope event:
UrlService.listen(false) stops the router from responding to URL changes entirely. Call listen(true) to resume. This is useful when loading states asynchronously and you want to defer URL-driven navigation until the states are registered:
.run(function($url,$stateRegistry){$url.listen(false);fetch('/api/states').then(r=>r.json()).then(function(states){states.forEach(s=>$stateRegistry.register(s));$url.listen(true);$url.sync();// activate the state matching the current URL
});});
9 - Animations
9.1 - CSS-based animations with the AngularTS CSS driver
Write CSS transitions and keyframe animations for AngularTS structural directives using ng-enter, ng-leave, ng-move, and stagger classes.
The CSS animation driver is the default mechanism for animating AngularTS structural directives. When a directive calls $animate.enter(), $animate.leave(), $animate.move(), $animate.addClass(), or $animate.removeClass(), the CSS driver reads the element’s computed transitionDuration and animationDuration after applying the appropriate preparation classes. If it detects a non-zero duration, it manages the full lifecycle: blocking premature transitions, applying active classes after a requestAnimationFrame, listening for transitionend and animationend events, and cleaning up all temporary classes when the animation finishes.
How the CSS driver works
The driver goes through a fixed sequence for every animation:
Preparation classes are added. For a structural event, this means .ng-enter, .ng-leave, or .ng-move. For class-based events, it means .foo-add or .foo-remove.
Transitions are temporarily blocked by applying a large negative transitionDelay inline style. This prevents the browser from computing a transition before the active class is applied.
The driver waits for the next quiet requestAnimationFrame. This forces the browser to flush style calculations, so getComputedStyle() returns accurate timing values.
Active classes are added (e.g., .ng-enter-active). The negative delay is removed at the same time, causing any defined CSS transition to start.
The driver listens for transitionend / animationend. A fallback setTimeout fires at delay + 1.5 * duration to handle browsers that may not fire the event reliably.
Cleanup. All preparation and active classes are removed, inline transition and animation style overrides are reverted, and the AnimateRunner is resolved.
Note: The CSS driver only runs an animation if getComputedStyle() reports a non-zero transitionDuration or animationDuration after the preparation classes are applied. If no duration is detected, the driver skips the animation and immediately resolves the runner.
CSS transitions
The simplest way to animate an element is to define CSS transitions on the preparation classes. The transition must be set on the preparation class (.ng-enter) and the final state on the active class (.ng-enter-active).
.my-element.ng-enter{transition:opacity0.3sease,transform0.3sease;opacity:0;transform:translateY(-10px);}/* The ending state — applied one rAF later to trigger the transition */.my-element.ng-enter-active{opacity:1;transform:translateY(0);}/* Leave animation — reverse the enter */.my-element.ng-leave{transition:opacity0.3sease,transform0.3sease;opacity:1;transform:translateY(0);}.my-element.ng-leave-active{opacity:0;transform:translateY(10px);}
CSS keyframe animations
You can also use @keyframes animations. Define the keyframe animation on the preparation class using the animation shorthand property:
With keyframe animations the active class (.ng-enter-active) is not required to drive the animation, but you can still use it to override or extend properties applied during the active phase.
Class-based transitions (ng-show / ng-hide)
When ng-show or ng-hide adds or removes the ng-hide class, $animate.addClass() and $animate.removeClass() are called internally. The CSS driver applies .ng-hide-add / .ng-hide-add-active for the hide transition and .ng-hide-remove / .ng-hide-remove-active for the show transition.
.my-panel.ng-hide-add{transition:opacity0.25sease;opacity:1;}.my-panel.ng-hide-add-active{opacity:0;}/* Fade in when revealed */.my-panel.ng-hide-remove{transition:opacity0.25sease;opacity:0;}.my-panel.ng-hide-remove-active{opacity:1;}
The same pattern applies to any class you add or remove via $animate.addClass() or $animate.removeClass(). If you call $animate.addClass(el, 'highlighted'), the driver applies .highlighted-add and .highlighted-add-active.
Example: animating ng-repeat list items
ng-repeat calls $animate.enter() when a new item is added, $animate.leave() when one is removed, and $animate.move() when the list is reordered.
<liclass="list-item"ng-repeat="item in items track by item.id"> {{ item.name }}
</li></ul>
When multiple elements animate simultaneously under the same parent — common with ng-repeat — the CSS driver detects a stagger class automatically. Define .ng-enter-stagger with transition-delay and zero transition-duration:
transition:opacity0.3sease,transform0.3sease;opacity:0;transform:translateY(8px);}.list-item.ng-enter-active{opacity:1;transform:translateY(0);}/* Stagger: each subsequent item is delayed by 80ms */.list-item.ng-enter-stagger{transition-delay:0.08s;transition-duration:0s;}
The driver reads the transitionDelay from .ng-enter-stagger and multiplies it by the item’s index within the batch. The first item starts immediately; each additional item is offset by the stagger delay.
CSS animations can be expensive when they trigger layout or paint on every frame. Follow these guidelines to keep animations smooth:
Use transform and opacity
transform and opacity are the only properties that browsers can animate entirely on the GPU compositor thread without triggering layout or paint. Prefer these over width, height, top, left, margin, or padding.
Avoid animating box-model properties
Properties like height, padding, and margin force layout recalculation on every frame. Use transform: scaleY() or max-height tricks as alternatives where possible.
Use will-change sparingly
Adding will-change: transform hints to the browser that the element will be animated, creating a new compositor layer. Use it only on elements you know will animate — overuse increases memory consumption.
Limit simultaneous animations
Use $animateProvider.classNameFilter() or $animateProvider.customFilter() to restrict animations to specific elements. Animating large numbers of DOM nodes simultaneously causes frame drops on low-powered devices.
9.2 - JavaScript-based animations with the AngularTS JS driver
Register JavaScript animation handlers with $animateProvider, implement enter/leave/move hooks with done callbacks, and use the Web Animations API.
The JavaScript animation driver lets you write fully imperative animations in code. Instead of defining CSS classes, you register a factory function against a CSS class selector. When an element carrying that class goes through a structural or class-based animation event, the driver looks up and invokes the matching handler. This makes the JS driver the right choice when you need precise timing control, want to integrate an animation library such as the Web Animations API, or need to coordinate multiple elements that CSS transitions cannot express.
How the JS driver works
At startup, AnimateJsDriverProvider registers itself with $$animationProvider._drivers. During each animation request, the animation queue calls drivers in reverse registration order — the JS driver is checked before the CSS driver. The driver calls $$animateJs(element, event, classes, options) which inspects the element’s class list against all factories registered via $animateProvider.register(). If a matching factory is found, it retrieves the singleton handler object from the injector and packages the appropriate lifecycle hook as a runnable operation.
The internal $$animateJs service (AnimateJsFn) handles two phases for most events:
before* — e.g., beforeAddClass, beforeRemoveClass. Runs synchronously before the DOM change.
after* (or the event name itself for enter, move) — runs after the DOM change.
For leave, the hooks are leave (before removal) and afterLeave (after removal). For enter and move, only the after-phase hook is called (named enter / move respectively), because the before-phase does not make sense for elements being inserted.
Note: The JS driver and CSS driver are not mutually exclusive per element, but the animation queue calls invokeFirstDriver() which returns on the first driver that produces a handler. If a JS animation is registered for an element, the CSS driver is skipped for that animation event.
Registering a JS animation
Use $animateProvider.register() during the config phase to associate a factory with a CSS class selector. The selector must begin with .. The factory is an injectable function that returns an object containing lifecycle hook methods.
$animateProvider.register('.fade',function(){return{enter:function(element,done){// animate element in, then call done()
element.style.opacity='0';requestAnimationFrame(function(){element.style.transition='opacity 0.3s ease';element.style.opacity='1';element.addEventListener('transitionend',functiononEnd(){element.removeEventListener('transitionend',onEnd);done();});});},leave:function(element,done){element.style.transition='opacity 0.3s ease';element.style.opacity='0';element.addEventListener('transitionend',functiononEnd(){element.removeEventListener('transitionend',onEnd);done();});},};});}]);
Or use the module-level .animation() shorthand, which calls $animateProvider.register() internally:
The object returned by your factory can implement any combination of these hooks. Unimplemented hooks are simply skipped.
Hook
Signature
When it fires
enter
(element, done)
After element is inserted into the DOM.
leave
(element, done)
Before element is removed from the DOM.
afterLeave
(element, done)
After element is removed from the DOM.
move
(element, done)
After element is moved to a new position.
beforeAddClass
(element, className, done)
Before the class is added to the element.
addClass
(element, className, done)
After the class has been added.
beforeRemoveClass
(element, className, done)
Before the class is removed.
removeClass
(element, className, done)
After the class has been removed.
beforeSetClass
(element, addedClasses, removedClasses, done)
Before the atomic add/remove.
setClass
(element, addedClasses, removedClasses, done)
After the atomic add/remove.
animate
(element, from, to, done)
For $animate.animate() calls.
The done callback
Every hook receives a done function as its last argument. You must call done() when the animation finishes — whether that is after a transitionend event, a setTimeout, a Web Animations API finish event, or any other mechanism. If done() is never called, the AnimateRunner associated with this animation will never resolve, blocking any chained work.
// If you return early (e.g., no animation needed), still call done()
if(window.matchMedia('(prefers-reduced-motion: reduce)').matches){done();return;}// Otherwise call done() when the animation actually finishes
runMyAnimation(element).then(done);}
You may also return a cleanup function from the hook. This function is invoked if the animation is cancelled before it completes:
constanimation=element.animate([{opacity:0},{opacity:1}],{duration:300,easing:'ease'});animation.onfinish=done;// Return a cancel handler
returnfunction(wasCancelled){if(wasCancelled){animation.cancel();}};}
Example: Web Animations API
The Web Animations API provides a clean way to drive animations imperatively. It returns a promise-like Animation object with onfinish and oncancel callbacks.
Apply the animation by adding the .pop-in class to any element managed by a structural directive:
<p>This panel animates in and out with the Web Animations API.</p></div>
Example: class-based JS animation
The addClass and removeClass hooks fire when $animate.addClass() or $animate.removeClass() is called — including internally by ng-show and ng-hide. The className argument is the space-separated string of classes being added or removed.
When you need to animate related elements in sequence — for example, a leaving element that exits while an entering element waits — you can share state via closure:
$$animateJs is the internal function that the JS driver uses to look up and package JS animation handlers. It is available as an injectable service if you need to call it directly — for example, when writing a custom driver or testing animation behavior.
It returns an Animator object ({ _willAnimate: true, start(), end() }) if at least one registered handler matches the element’s class list, or undefined if no handler is found. The returned Animator.start() runs the before-phase and after-phase operations, and calls runner.complete(status) when both are done.
Injecting services into animation factories
Animation factory functions participate in dependency injection. List dependencies in the array notation or use $inject:
return{enter:function(element,done){$log.debug('enter animation started');// e.g., fetch data to drive animation parameters
$http.get('/api/animation-config').then(function(response){constduration=response.data.duration||300;element.animate([{opacity:0},{opacity:1}],{duration,fill:'forwards'}).onfinish=done;});},};}]);
Warning: Long-running asynchronous work inside animation hooks (such as HTTP requests) can make your UI feel sluggish. Prefer pre-fetching animation configuration and caching it rather than fetching it inside a hook on every animation.
Combining JS and CSS animations
If you want the JS driver to apply classes and then let CSS transitions handle the visual animation, you can manipulate classes directly in the hook and detect completion via a transitionend listener. This approach gives you the control of JS hooks with the performance of CSS compositing:
Tip: When coordinating JS and CSS this way, always use transform and opacity for the animated properties so the browser can run the transition on the compositor thread without layout recalculation.
9.3 - AngularTS animations: CSS and JavaScript drivers overview
Overview of the AngularTS animation system — the $animate service, CSS and JS drivers, structural directive hooks, and class-based transitions.
AngularTS ships a first-class animation system built into the core framework. When you use structural directives such as ng-if, ng-repeat, ng-show, ng-hide, ng-include, or ng-view, the framework automatically coordinates with the $animate service to apply CSS class hooks and invoke registered JavaScript animation handlers at the exact moment DOM changes occur — before and after insertion, removal, or class toggling.
How animations are triggered
Animations in AngularTS are not triggered by calling an animation API directly. Instead, they are a side-effect of normal directive activity. When ng-if removes an element, it calls $animate.leave() internally. When ng-repeat inserts a new item, it calls $animate.enter(). This means you never need to change your directive usage — you only need to provide CSS rules or a registered JavaScript animation for the matching class names.
The $animate service sits between directives and the animation drivers. It queues animation work, deduplicates competing animations on the same element, and dispatches to whichever driver is configured. All animation requests are deferred until after the current digest cycle completes, so DOM changes and class mutations are always applied in a stable, predictable order.
The two animation drivers
AngularTS provides two built-in drivers that are consulted in sequence. The JS driver is checked first; if it returns a handler, the CSS driver is skipped for that element. If no JS handler matches, the CSS driver reads the element’s computed styles to detect transitions or keyframe animations.
Reads transitionDuration, animationDuration, and related computed style properties after applying preparation classes. Handles staggering, delays, and both CSS transitions and @keyframes animations with no JavaScript required.
Invokes factory functions registered via $animateProvider.register(). Each factory returns an object with lifecycle hooks (enter, leave, move, addClass, removeClass, setClass, animate) that receive a done callback. Suitable for Web Animations API, GSAP, or any imperative animation library.
CSS class hooks
The CSS driver applies a pair of classes for every animation event. The first class (the preparation class) is added immediately; the second class (the active class) is added one requestAnimationFrame later so the browser can compute a transition between the two states. Both classes are removed when the animation completes.
Event
Preparation class
Active class
enter
.ng-enter
.ng-enter-active
leave
.ng-leave
.ng-leave-active
move
.ng-move
.ng-move-active
addClass foo
.foo-add
.foo-add-active
removeClass foo
.foo-remove
.foo-remove-active
During structural animations (enter, leave, move), the element also receives .ng-animate for the full duration of the animation.
For staggered animations — such as list items entering one after another — define a stagger delay class:
The CSS driver detects .ng-enter-stagger automatically when more than one element is being animated simultaneously under the same parent.
The $animate service API
The $animate service is injectable and provides the full animation API. Every method returns an AnimateRunner that you can use to react to completion or cancel the animation early.
static$inject=['$animate','$element'];constructor(private$animate: ng.AnimateService,private$element: HTMLElement,){}showPanel(panelEl: HTMLElement){// Insert panelEl after this.$element; triggers ng-enter
this.$animate.enter(panelEl,this.$element.parentElement,this.$element);}hidePanel(panelEl: HTMLElement){// Remove panelEl after the leave animation completes
this.$animate.leave(panelEl);}highlight(el: HTMLElement){// Add 'highlighted' class with an animation
this.$animate.addClass(el,'highlighted');}updateClasses(el: HTMLElement){// Add and remove classes atomically
this.$animate.setClass(el,'active','inactive');}morphStyle(el: HTMLElement){// Animate from one set of inline styles to another
this.$animate.animate(el,{opacity: 0,transform:'scale(0.8)'},{opacity: 1,transform:'scale(1)'},'my-morph',);}}
Full method signatures
Method
Description
enter(element, parent?, after?, options?)
Insert element into the DOM and trigger an enter animation.
leave(element, options?)
Trigger a leave animation, then remove the element.
move(element, parent, after?, options?)
Move element within the DOM and trigger a move animation.
addClass(element, className, options?)
Add one or more CSS classes with an animation.
removeClass(element, className, options?)
Remove one or more CSS classes with an animation.
setClass(element, add, remove, options?)
Add and remove classes as a single atomic animation.
animate(element, from, to, className?, options?)
Animate from one set of inline styles to another.
cancel(runner)
Cancel a running animation; the end state is still applied.
Observing animation completion
Every $animate method returns an animation handle. Use done() when code needs to run after an animation settles, or pass onStart, onDone, and onCancel callbacks in native animation options when the callback belongs to one request.
Two provider-level hooks let you restrict which elements can be animated. Both are configured during the config phase via $animateProvider.
$animateProvider.classNameFilter(regex) — only animate elements whose class list matches the given regular expression:
// Only animate elements that have an 'animate-' prefixed class
$animateProvider.classNameFilter(/\banimate-/);}]);
$animateProvider.customFilter(fn) — supply an arbitrary predicate that receives (node, event, options) and returns true to allow the animation:
$animateProvider.customFilter(function(node,event){// Skip all animations when in reduced-motion mode
return!window.matchMedia('(prefers-reduced-motion: reduce)').matches;});}]);
Tip: Keep both filter functions as lean as possible. They are called for every DOM operation performed by animation-aware directives.
Registering JavaScript animations
To register a JavaScript animation, call $animateProvider.register() during the config phase or use the module-level .animation() shorthand. The name must be a CSS class selector starting with .:
$animateProvider.register('.fade-animation',['$q',function($q){return{enter(element,done){// run enter animation, call done() when finished
done();},leave(element,done){done();},};}]);}]);
The registered animation is matched against the element’s class list. If the element has .fade-animation when an enter event fires, the enter hook is invoked.
ng-animate-swap
The ng-animate-swap directive swaps between transcluded blocks as a watched expression changes. The previous element is removed with a leave animation and the new element is inserted with an enter animation, making it simple to animate between different states without manual DOM management.
<divclass="panel">{{ currentView }}</div></div>
The directive runs at priority 550, after ng-if (600) but before most others, so it cooperates correctly with other structural directives.
ng-animate-children
By default, when a parent structural animation (enter, leave, or move) is running, child animations on descendants are suppressed. This prevents visual chaos when an entire subtree is animated at once. The ng-animate-children attribute overrides this behavior for a specific container.
<divng-if="showPanel"ng-animate-children="true"><divng-repeat="item in items"class="list-item">{{ item }}</div></div>
Setting ng-animate-children to "on", "true", or an empty string enables child animations. Setting it to any other value (or omitting it) defers to the default suppression behavior.
10 - Filters
10.1 -
/**
@ngdoc filter
@name filter
@kind function
@description
Selects a subset of items from array and returns it as a new array.
@param {Array} array The source array.
Note: If the array contains objects that reference themselves, filtering
is not possible.
@param {string|Object|function()} expression The predicate to be used for
selecting items from
array.
Can be one of:
string: The string is used for matching against the contents of the
array. All strings or
objects with string properties in `array` that match this string will be returned. This also
applies to nested object properties.
The predicate can be negated by prefixing the string with `!`.
Object: A pattern object can be used to filter specific properties on
objects contained
by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
which have property `name` containing "M" and property `phone` containing "1". A special
property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match
against any property of the object or its nested object properties. That's equivalent to the
simple substring match with a `string` as described above. The special property name can be
overwritten, using the `anyPropertyKey` parameter.
The predicate can be negated by prefixing the string with `!`.
For example `{name: "!M"}` predicate will return an array of items which have property `name`
not containing "M".
Note that a named property will match properties on the same level only, while the special
`$` property will match properties on the same level or deeper. E.g. an array item like
`{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
**will** be matched by `{$: 'John'}`.
function(value, index, array): A predicate function can be used to write
arbitrary filters.
The function is called for each element of the array, with the element, its index, and
the entire array itself as arguments.
The final result is an array of those elements that the predicate returned true for.
@param {function(actual, expected)|true|false} [comparator] Comparator which
is used in
determining if values retrieved using `expression` (when it is not a function) should be
considered a match based on the expected value (from the filter expression) and actual
value (from the object in the array).
Can be one of:
function(actual, expected):
The function will be given the object value and the predicate value to compare and
should return true if both values should be considered equal.
true: A shorthand for strict value comparison.
This is essentially strict comparison of expected and actual.
false: A short hand for a function which will look for a substring match
in a case
insensitive way. Primitive values are converted to strings. Objects are not compared against
primitives, unless they have a custom `toString` method (e.g. `Date` objects).
Defaults to false.
@param {string} [anyPropertyKey] The special property name that matches
against any property.
By default `$`.
*/
10.2 -
JSON Filter
Description
Allows you to convert a JavaScript object into a JSON string.
This filter is mostly useful for debugging. When using the double curly
{{value}} notation, the binding is automatically converted to JSON.
Parameters
object{*}: Any JavaScript object (including arrays and primitive types)
to filter.
spacing{number=}: The number of spaces to use per indentation, defaults
to 2.
Returns
{string}: JSON string.
10.3 -
limitTo Filter
Description
Creates a new array or string containing only a specified number of elements.
The elements are taken from either the beginning or the end of the source array,
string, or number, as specified by the value and sign (positive or negative) of
limit. Other array-like objects are also supported (e.g., array subclasses,
NodeLists, JQLite/jQuery collections, etc.). If a number is used as input, it is
converted to a string.
Parameters
input{Array|ArrayLike|string|number}: Array/array-like, string, or
number to be limited.
limit{string|number}: The length of the returned array or string.
If the limit number is positive, limit number of items from the
beginning of the source array/string are copied.
If the number is negative, limit number of items from the end of the
source array/string are copied.
The limit will be trimmed if it exceeds array.length.
If limit is undefined, the input will be returned unchanged.
begin{(string|number)=}: Index at which to begin limitation. As a
negative index, begin indicates an offset from the end of input. Defaults
to 0.
Returns
{Array|string}: A new sub-array or substring of length limit or less if
the input had less than limit elements.
10.4 -
OrderBy Filter
Description
Returns an array containing the items from the specified collection, ordered
by a comparator function based on the values computed using the expression
predicate.
For example, [{id: 'foo'}, {id: 'bar'}] | orderBy:'id' would result in
[{id: 'bar'}, {id: 'foo'}].
The collection can be an Array or array-like object (e.g., NodeList, jQuery
object, TypedArray, String, etc).
The expression can be a single predicate or a list of predicates, each serving
as a tie-breaker for the preceding one. The expression is evaluated against
each item and the output is used for comparing with other items.
You can change the sorting order by setting reverse to true. By default,
items are sorted in ascending order.
The comparison is done using the comparator function. If none is specified, a
default, built-in comparator is used (see below for details - in a nutshell, it
compares numbers numerically and strings alphabetically).
Under the Hood
Ordering the specified collection happens in two phases:
All items are passed through the predicate (or predicates), and the returned
values are saved along with their type (string, number, etc). For
example, an item {label: 'foo'}, passed through a predicate that extracts
the value of the label property, would be transformed to:
{value:'foo',type:'string',index:...}
Note: null values use ’null’ as their type. 2. The comparator function is used
to sort the items, based on the derived values, types, and indices.
If you use a custom comparator, it will be called with pairs of objects of the
form {value: …, type: ‘…’, index: …} and is expected to return 0 if the
objects are equal (as far as the comparator is concerned), -1 if the 1st one
should be ranked higher than the second, or 1 otherwise.
To ensure that the sorting will be deterministic across platforms, if none of
the specified predicates can distinguish between two items, orderBy will
automatically introduce a dummy predicate that returns the item’s index as
value. (If you are using a custom comparator, make sure it can handle this
predicate as well.)
If a custom comparator still can’t distinguish between two items, then they will
be sorted based on their index using the built-in comparator.
Finally, in an attempt to simplify things, if a predicate returns an object as
the extracted value for an item, orderBy will try to convert that object to a
primitive value before passing it to the comparator. The following rules govern
the conversion:
If the object has a valueOf() method that returns a primitive, its return value
will be used instead. (If the object has a valueOf() method that returns another
object, then the returned object will be used in subsequent steps.) If the
object has a custom toString() method (i.e., not the one inherited from Object)
that returns a primitive, its return value will be used instead. (If the object
has a toString() method that returns another object, then the returned object
will be used in subsequent steps.) No conversion; the object itself is used. The
Default Comparator The default, built-in comparator should be sufficient for
most use cases. In short, it compares numbers numerically, strings
alphabetically (and case-insensitively), for objects falls back to using their
index in the original collection, sorts values of different types by type, and
puts undefined and null values at the end of the sorted list.
More specifically, it follows these steps to determine the relative order of
items:
If the compared values are of different types: If one of the values is
undefined, consider it “greater than” the other. Else if one of the values is
null, consider it “greater than” the other. Else compare the types themselves
alphabetically. If both values are of type string, compare them alphabetically
in a case- and locale-insensitive way. If both values are objects, compare their
indices instead. Otherwise, return: 0, if the values are equal (by strict
equality comparison, i.e., using ===). -1, if the 1st value is “less than” the
2nd value (compared using the < operator). 1, otherwise. Note: If you notice
numbers not being sorted as expected, make sure they are actually being saved as
numbers and not strings. Note: For the purpose of sorting, null and undefined
are considered “greater than” any other value (with undefined “greater than”
null). This effectively means that null and undefined values end up at the end
of a list sorted in ascending order. Note: null values use ’null’ as their type
to be able to distinguish them from objects.
Parameters collection {Array|ArrayLike}: The collection (array or array-like
object) to sort.
expression {(Function|string|Array.<Function|string>)=}: A predicate (or list of
predicates) to be used by the comparator to determine the order of elements.
Can be one of:
Function: A getter function. This function will be called with each item as an
argument and the return value will be used for sorting. string: An AngularTS
expression. This expression will be evaluated against each item and the result
will be used for sorting. For example, use ’label’ to sort by a property called
label or ’label.substring(0, 3)’ to sort by the first 3 characters of the label
property. (The result of a constant expression is interpreted as a property name
to be used for comparison. For example, use ‘“special name”’ (note the extra
pair of quotes) to sort by a property called special name.) An expression can be
optionally prefixed with + or - to control the sorting direction, ascending or
descending. For example, ‘+label’ or ‘-label’. If no property is provided,
(e.g., ‘+’ or ‘-’), the collection element itself is used in comparisons. Array:
An array of function and/or string predicates. If a predicate cannot determine
the relative order of two items, the next predicate is used as a tie-breaker.
Note: If the predicate is missing or empty, then it defaults to ‘+’.
reverse {boolean=}: If true, reverse the sorting order.
comparator {(Function)=}: The comparator function used to determine the relative
order of value pairs. If omitted, the built-in comparator will be used.
Returns {Array}: The sorted array.
11 - Values
11.1 - $document
Injectable window.document object
Description
An injectable wrapper for window.documentobject . Useful for
mocking a browser dependency in non-browser environment tests:
Example:
// value injectables are overriden
angular.module('demo',[]).value('$document',{});
When combined with ng-inject directive, the wrapper also makes document
object directly accessible in the template scope.