Data Binding Directives in AngularTS Explained

Explore ng-bind, ng-bind-html, ng-model, ng-class, ng-style, and ng-init with real examples covering one-way and two-way data binding.

Data binding directives synchronise values between the scope and the DOM without requiring you to write event listeners or DOM queries by hand. AngularTS provides one-way and two-way binding variants to cover every use case, from safe text output to full form synchronisation.

ng-bind

ng-bind is the attribute equivalent of double-curly interpolation ({{ }}). It watches the given scope expression and writes the result as the element’s textContent. Because it sets textContent, it is immune to XSS — no HTML is ever parsed.

<p>Hello, {{ user.name }}!</p>

<!-- Using ng-bind — element is empty until AngularTS compiles -->
<p>Hello, <span ng-bind="user.name"></span>!</p>

The implementation observes the expression’s reactive dependencies and updates the text when one of them changes.

Tip: Prefer ng-bind over {{ }} in the <body> of server-rendered pages to avoid the flash of uncompiled template (FOUC). The element starts empty and is filled when Angular bootstraps.

Parameters

ng-bind

  • Type: expression
  • Required: yes

Any AngularTS expression. The result is converted to a string via stringify() and written to element.textContent. null and undefined render as an empty string.


ng-bind-template

ng-bind-template lets you embed multiple interpolated expressions inside a single attribute value — useful when the surrounding text cannot hold a child element.

<title ng-bind-template="{{pageTitle}} — {{siteName}}"></title>

<!-- Equivalent using child elements (not possible inside <title>) -->

The directive reacts to interpolation dependencies and writes the resulting string to textContent.

ng-bind-template

  • Type: string with {{ }} expressions
  • Required: yes

A string literal containing one or more {{ expression }} placeholders. The entire interpolated string is written to textContent.


ng-bind-html

ng-bind-html inserts the expression result directly into element.innerHTML. Use this directive when you need to render server-provided or pre-sanitised markup. It calls $parse during compilation to check for interpolation errors, then watches the expression and sets innerHTML on every change.

<div ng-bind-html="article.body"></div>
  .controller('ArticleCtrl', ['$scope', function($scope) {
    $scope.article = {
      body: '<p>Hello <strong>world</strong></p>'
    };
  }]);

Warning: ng-bind-html sets innerHTML directly. Always sanitise content on the server before placing it in scope. Avoid interpolating raw user input with this directive.

ng-bind-html

  • Type: expression
  • Required: yes

An expression evaluating to a string of HTML. The string is written to element.innerHTML. null and undefined clear the element.


ng-model

ng-model establishes a two-way binding between a form input and a scope property. Changes to the input update the scope; changes to the scope property update the input. It is the backbone of AngularTS form handling.

Text input

<input type="text" ng-model="user.name" />
<p>Hello, {{ user.name }}!</p>

Checkbox

<input type="checkbox" ng-model="settings.notifications" />
<p ng-bind="settings.notifications ? 'On' : 'Off'"></p>

Select

<select ng-model="selected.country">
  <option value="us">United States</option>
  <option value="gb">United Kingdom</option>
</select>
<p>You selected: {{ selected.country }}</p>

Textarea

<textarea ng-model="message.body" rows="4"></textarea>
<p>Characters: {{ message.body.length }}</p>

ng-model creates an NgModelController instance that manages:

  • viewValue — the formatted value shown in the control (always a string for native inputs)
  • modelValue — the parsed value stored in the 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

PropertyTypeDescription
pristinebooleantrue if the user has not interacted with this control
dirtybooleantrue after the user has changed the value
touchedbooleantrue after the control has lost focus
untouchedbooleantrue before the control has ever been blurred
validbooleantrue if all validators pass
invalidbooleantrue if any validator fails

CSS classes

AngularTS automatically toggles CSS classes on the element:

.ng-valid {
  border-color: green;
}

/* Applied when the model is invalid */
.ng-invalid {
  border-color: red;
}

/* Applied when the user has not yet changed the value */
.ng-pristine {
}

/* Applied once the user has changed the value */
.ng-dirty {
}

/* Applied once the input has been blurred */
.ng-touched {
}

ng-model

  • Type: expression
  • Required: yes

An assignable AngularTS expression. The expression must be assignable (pointing to a scope property), otherwise AngularTS throws an ngModel:nonassign error.


ng-class

ng-class conditionally adds and removes CSS classes based on a scope expression. It supports three input formats: an object, an array, or a string.

Object syntax

Keys are class names; values are expressions. A class is applied when its value is truthy.

<div ng-class="{ active: isActive, 'text-danger': hasError }">Status panel</div>
$scope.isActive = true;
$scope.hasError = false;
// Result: class="active"

For larger views, prefer projecting domain state into a view-model class map and binding that map directly. This keeps templates readable and lets JavaScript type checking validate the object shape.

<button ng-class="tile.classes">Fire</button>
/**
 * @param {{ state: string, sunk: boolean }} tile
 * @returns {ng.ClassMap}
 */
function tileClasses(tile) {
  return {
    placed: tile.state === 'unit',
    hit: tile.state === 'hit',
    miss: tile.state === 'miss',
    sunk: tile.sunk,
  };
}

$scope.tile = {
  state: 'unit',
  sunk: false,
  classes: tileClasses({ state: 'unit', sunk: false }),
};

Array syntax

Each element is evaluated as a class name or object. Useful when combining static and conditional classes.

<div ng-class="[baseClass, { highlighted: isSelected }]">Item</div>
$scope.baseClass = 'card';
$scope.isSelected = true;
// Result: class="card highlighted"

String syntax

The expression evaluates to a space-separated class string.

<div ng-class="currentTheme">Themed content</div>
$scope.currentTheme = 'theme-dark compact';
// Result: class="theme-dark compact"

The implementation uses reference counting internally (digestClassCounts) so that when multiple ng-class directives compete on the same element, classes are not prematurely removed while still in use.

Alternating repeated rows

Use the repeater’s $even and $odd locals in a normal ng-class map.

<ul>
  <li
    ng-repeat="item in items"
    ng-class="{ 'row-even': $even, 'row-odd': $odd }"
  >
    {{ item.name }}
  </li>
</ul>

ng-class

  • String — a space-delimited list of class names.
  • Object — keys are class names, values are truthy/falsy conditions.
  • Array — each element is recursively processed using the above rules.

ng-style

ng-style watches a scope object and applies its key-value pairs as inline CSS properties using element.style.setProperty. When the expression changes, the old properties are first removed before the new ones are applied.

<div ng-style="boxStyles">Dynamic box</div>
  'background-color': '#4f46e5',
  'color': '#ffffff',
  'padding': '16px',
  'border-radius': '8px'
};
<p
  ng-style="{ 'font-size': fontSize + 'px', 'font-weight': isBold ? 'bold' : 'normal' }"
>
  Styled text
</p>

Note: CSS property names must use hyphen-case (background-color, not backgroundColor) since the implementation calls element.style.setProperty rather than assigning to element.style[key].

ng-style

  • Type: object
  • Required: yes

An expression evaluating to an object where keys are CSS property names in hyphen-case and values are CSS value strings. Setting the expression to null or undefined removes all previously applied inline styles.


ng-init

ng-init evaluates an expression during the pre-link phase — before child directives are linked. It is most useful for initialising scope variables inline without requiring a separate controller.

<div ng-init="count = 0; title = 'Hello'">
  <button ng-click="count = count + 1">Clicked {{ count }} times</button>
</div>
<ul>
  <li ng-repeat="item in items" ng-init="pos = $index + 1">
    {{ pos }}. {{ item.name }}
  </li>
</ul>

The implementation checks whether a controller is present on the element (via getController) and, if so, evaluates the expression on the controller’s scope. Otherwise it falls back to the current scope.

Warning: Use ng-init sparingly. For any non-trivial initialisation, use a controller instead. Keeping logic in templates makes it harder to test and maintain.

ng-init

  • Type: expression
  • Required: yes

An AngularTS expression or semicolon-separated list of expressions evaluated once in the pre-link phase. The expression has access to the current scope.