Expressions & Data Binding

Anything inside {{ }} is an AngularJS expression — a small snippet of JavaScript-like code that gets evaluated against the current scope and written into the page. Expressions and two-way binding together are the two ideas that made AngularJS feel different from plain jQuery-style DOM scripting when it first appeared.

What counts as an expression

Expressions support arithmetic, string concatenation, property access, and simple ternaries — a deliberately smaller subset of JavaScript than a full <script> block:

HTML expressions.html
<div ng-app="" ng-init="price = 40, qty = 3">
  <p>Total: {{ price * qty }}</p>
  <p>{{ qty > 1 ? qty + ' items' : qty + ' item' }}</p>
</div>
Rendered output
Total: 120
3 items

Both expressions run against the scope created by ng-init, which is where price and qty live. The ternary works the same way it does in plain JavaScript, just without needing a <script> tag anywhere.

Expressions fail silently

This is the biggest practical difference from real JavaScript: a normal <script> throws and stops execution on an error, but an AngularJS expression that references something undefined just renders nothing, with no error visible on the page:

HTML typo.html
<div ng-app="" ng-init="user = { name: 'Priya' }">
  <p>Welcome, {{ user.nmae }}</p>
</div>
Rendered output
Welcome,

The typo nmae instead of name means the expression evaluates to undefined, which AngularJS quietly renders as nothing — no console error, no broken page, just a blank space where "Priya" should be. This is convenient while a page is still loading data asynchronously (nothing crashes while a value is momentarily missing), but it also means typos like this one can sit unnoticed for a long time.

Two-way binding, revisited

The reason ng-model feels different from manually reading input.value is that AngularJS doesn't wait for you to ask — it re-checks bound expressions on its own after anything that could have changed them (a click, a keystroke, an HTTP response) finishes, in a process called the digest cycle. Every {{ }} and every ng-model on the page gets re-evaluated during that cycle, and the DOM updates wherever a value actually changed.

Why this matters for performance: every expression on a page gets re-checked on every digest cycle, not just the ones that changed. A page with a few dozen bindings won't notice; a page with several thousand (a huge ng-repeat, for instance) can start to feel sluggish, because AngularJS is comparing thousands of old and new values on every single interaction. This is one of the concrete reasons later frameworks moved to different change-detection strategies.