Data Binding Directives in AngularTS Explained
Data binding directives synchronise values between the scope and the DOM without requiring you to write event listeners or DOM queries by hand. AngularTS provides one-way and two-way binding variants to cover every use case, from safe text output to full form synchronisation.
ng-bind
ng-bind is the attribute equivalent of double-curly interpolation ({{ }}). It watches the given scope expression and writes the result as the element’s textContent. Because it sets textContent, it is immune to XSS — no HTML is ever parsed.
<p>Hello, {{ user.name }}!</p>
<!-- Using ng-bind — element is empty until AngularTS compiles -->
<p>Hello, <span ng-bind="user.name"></span>!</p>
The implementation watches the expression on every digest. The lazy attribute defers the first watch until a digest is explicitly triggered:
<span ng-bind="heavyExpression" lazy></span>
Tip: Prefer
ng-bindover{{ }}in the<body>of server-rendered pages to avoid the flash of uncompiled template (FOUC). The element starts empty and is filled when Angular bootstraps.
Parameters
ng-bind
- Type:
expression - Required: yes
Any AngularTS expression. The result is converted to a string via stringify() and written to element.textContent. null and undefined render as an empty string.
ng-bind-template
ng-bind-template lets you embed multiple interpolated expressions inside a single attribute value — useful when the surrounding text cannot hold a child element.
<title ng-bind-template="{{pageTitle}} — {{siteName}}"></title>
<!-- Equivalent using child elements (not possible inside <title>) -->
The directive 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.
<div ng-bind-html="article.body"></div>
.controller('ArticleCtrl', function($scope) {
$scope.article = {
body: '<p>Hello <strong>world</strong></p>'
};
});
Warning:
ng-bind-htmlsetsinnerHTMLdirectly. Always sanitise content on the server before placing it in scope. Avoid interpolating raw user input with this directive.
ng-bind-html
- Type:
expression - Required: yes
An expression evaluating to a string of HTML. The string is written to element.innerHTML. null and undefined clear the element.
ng-model
ng-model establishes a two-way binding between a form input and a scope property. Changes to the input update the scope; changes to the scope property update the input. It is the backbone of AngularTS form handling.
Text input
<input type="text" ng-model="user.name" />
<p>Hello, {{ user.name }}!</p>
Checkbox
<input type="checkbox" ng-model="settings.notifications" />
<p ng-bind="settings.notifications ? 'On' : 'Off'"></p>
Select
<select ng-model="selected.country">
<option value="us">United States</option>
<option value="gb">United Kingdom</option>
</select>
<p>You selected: {{ selected.country }}</p>
Textarea
<textarea ng-model="message.body" rows="4"></textarea>
<p>Characters: {{ message.body.length }}</p>
ng-model creates an NgModelController instance that manages:
$viewValue— the formatted value shown in the control (always a string for native inputs)$modelValue— the parsed value stored in the 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.
<div ng-class="{ active: isActive, 'text-danger': hasError }">
Status panel
</div>
$scope.isActive = true;
$scope.hasError = false;
// Result: class="active"
For larger views, prefer projecting domain state into a view-model class map and binding that map directly. This keeps templates readable and lets JavaScript type checking validate the object shape.
<button ng-class="tile.classes">
Fire
</button>
/**
* @param {{ state: string, sunk: boolean }} tile
* @returns {ng.ClassMap}
*/
function tileClasses(tile) {
return {
placed: tile.state === 'unit',
hit: tile.state === 'hit',
miss: tile.state === 'miss',
sunk: tile.sunk,
};
}
$scope.tile = {
state: 'unit',
sunk: false,
classes: tileClasses({ state: 'unit', sunk: false }),
};
Array syntax
Each element is evaluated as a class name or object. Useful when combining static and conditional classes.
<div ng-class="[baseClass, { highlighted: isSelected }]">
Item
</div>
$scope.baseClass = 'card';
$scope.isSelected = true;
// Result: class="card highlighted"
String syntax
The expression evaluates to a space-separated class string.
<div ng-class="currentTheme">
Themed content
</div>
$scope.currentTheme = 'theme-dark compact';
// Result: class="theme-dark compact"
The implementation uses reference counting internally (digestClassCounts) so that when multiple ng-class directives compete on the same element, classes are not prematurely removed while still in use.
ng-class-even / ng-class-odd
These variants apply classes only to even- or odd-indexed rows inside an ng-repeat.
<li ng-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.
<div ng-style="boxStyles">
Dynamic box
</div>
'background-color': '#4f46e5',
'color': '#ffffff',
'padding': '16px',
'border-radius': '8px'
};
<p ng-style="{ 'font-size': fontSize + 'px', 'font-weight': isBold ? 'bold' : 'normal' }">
Styled text
</p>
Note: CSS property names must use hyphen-case (
background-color, notbackgroundColor) since the implementation callselement.style.setPropertyrather than assigning toelement.style[key].
ng-style
- Type:
object - Required: yes
An expression evaluating to an object where keys are CSS property names in hyphen-case and values are CSS value strings. Setting the expression to null or undefined removes all previously applied inline styles.
ng-init
ng-init evaluates an expression during the pre-link phase — before child directives are linked. It is most useful for initialising scope variables inline without requiring a separate controller.
<div ng-init="count = 0; title = 'Hello'">
<button ng-click="count = count + 1">Clicked {{ count }} times</button>
</div>
<ul>
<li ng-repeat="item in items" ng-init="pos = $index + 1">
{{ pos }}. {{ item.name }}
</li>
</ul>
The implementation checks whether a controller is present on the element (via getController) and, if so, evaluates the expression on the controller’s scope. Otherwise it falls back to the current scope.
Warning: Use
ng-initsparingly. 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.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.