Angular Expressions

Angular Expressions Header

One of the first things a developer writes in Angular, other than the ng-app directive, is an expression. This is easily identified as the code written inside of a binding {{ }} or directive.

<input type="text" ng-model="name" />
{{'Hello ' + name + '!'}}

In this example, 'Hello ' + name + '!' is the expression. The official Angular documentation is pretty clear (maybe it wasn’t clear in earlier versions) that bindings and expressions are distinct items. However, there are (highly-ranked) places on the internet listed in search results that don’t always acknowledge the difference so readers beware. While you naturally find expressions and bindings together, they are not the same. This post is dedicated to explaining how expressions serve a broad and important role in the Angular framework beyond just data binding.

Expressions in a Nutshell

A better way to summarize Angular expressions is that they are a way to write JavaScript in HTML. Writing JavaScript in HTML? If you immediately cringe when reading that, it’s OK. You probably have been taught that you shouldn’t write JavaScript in your HTML because JavaScript is for functionality and HTML is for structure and you want to keep those concerns separate. Separation of concerns is still important when using expressions and thankfully Angular allows only a subset of JavaScript expressions in an HTML view.

The key differentiator of an Angular expression is that it is executed in an encapsulated scope. This means you don’t have to worry about global objects conflicting as you normally would writing JavaScript in HTML. In general, the scope in which an Angular expression runs is defined by a controller. If no controller is present, expressions execute against a default scope.

Also, expressions are converted to JavaScript functions using Angular’s $parse service. The $parse service provides many benefits and enforces certain limitations that you should understand.

Limitations or Separations of Concern

Angular expressions have limitations when compared to standard JavaScript. The limitations, however, are reasonable when you consider the role expressions play in the overall Angular framework.

There is no access to global variables or objects in Angular expressions meaning there is no access to the document or the window objects directly. To access these objects, use the testable $document and $window wrappers in your controller. Scott Allen has a good example illustrating this functionality.

Also, no control flow is allowed in an expression, meaning that you cannot use conditional logic (including ternary expressions), loops, or exceptions. You also cannot declare functions within an expression and you cannot use the comma or void operators.

There are also some limitations around which operators are supported. Even when they are supported, they may not work as you would expect. For instance while {{ 1 + 1 }} displays 2, if one of those values comes from a text input, the values will concatenate a string 11. Futher, the ++ operator is not allowed. Comparison operators such as >, <=, and == generally work as expected but you can save yourself some headache by moving this logic into a function on the controller.

Here are two expression examples. The first example demonstrates what is possible with expressions. The second example shows how to move the logic into a controller.

Powerful Expression Example

<!DOCTYPE html>
<html ng-app>
<head>
    <title>Dining Calculator</title>
</head>
<body>
    <input type="number" ng-model="totalBill" placeholder="Total Bill" />
    <input type="number" ng-model="tipPercent" placeholder="Tip Percentage" />
    <input type="number" ng-model="peopleAmt" placeholder="Amount of People" />
    <div>{{((totalBill + totalBill * tipPercent/100) / peopleAmt) || 'Calculating...'}}</div>
    <script src="Scripts/angular.min.js"></script>
</body>
</html>

Using a Controller

<!DOCTYPE html>
<html ng-app="app">
<head>
    <title></title>
</head>
<body ng-controller="Main as vm">
    <input type="number" ng-model="vm.totalBill" ng-change="vm.calculateTotal()" placeholder="Total Bill" />
    <input type="number" ng-model="vm.tipPercent" ng-change="vm.calculateTotal()" placeholder="Tip Percentage" />
    <input type="number" ng-model="vm.peopleAmt" ng-change="vm.calculateTotal()" placeholder="Amount of People" />
    <div>{{vm.totalPerPerson}}</div>
    <script src="Scripts/angular.min.js"></script>
    <script>
        (function () {
            'use strict';

            angular.module('app', [])
                .controller('Main', main);                

            function main() {
                var vm = this,
                    CALCULATING_MSG = 'Calculating...';

                vm.calculateTotal = function () {
                    var totalPlusTip = vm.totalBill + vm.totalBill * vm.tipPercent / 100;
                    var amtPerPerson = totalPlusTip / vm.peopleAmt;

                    vm.totalPerPerson = amtPerPerson || CALCULATING_MSG;
                }

                vm.calculateTotal();

                return vm;
            }
        })();
    </script>
</body>
</html>

You’ll see in the first example that the expression used is quite powerful. There is a fair amount of math involved and it can even check for the falsy value NaN in order to show valuable information to the user.

The controller example at first glance is significantly more code than the first. Looks can be deceiving, however. Once required to apply any validation or formatting to the first example, the expression won’t hold up because it requires the introduction of control flow into the logic – which is not allowed in Angular expressions.

Another key difference is found when looking at only the HTML markup. Even though there is more HTML markup in the controller example, it reads easier because the function names label what the expression does. In addition, debugging the logic in the controller example is easier.

Again, the generally appropriate way to handle Angular expression limitations is to keep logic out of HTML views and instead move it into controllers or services. The limitations help to nudge you into writing cleaner, more maintainable code.

Benefits

In the previous section, you saw how expressions offer a subset of JavaScript in HTML. Angular expressions also offer many benefits above and beyond what JavaScript typically provides including graceful handling of null and undefined, use with directives, and filters.

One area where Angular expressions shine is in their ability to gracefully handle null and undefined values. Here is an example of code that would cause problems with traditional JavaScript UI code.

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <span id="dSpan"></span>
    <script>
        (function () {
            'use strict';

            var vm = {};
            dSpan.innerHTML = vm.foo;

        })();        
    </script>
</body>
</html>

When this code executes, the UI displays the word undefined. While having an undefined property in code is less than ideal, the user doesn’t need to see this. Further, if you expand the statement to dSpan.innerHTML = vm.foo.bar;, your application will throw a TypeError bringing your JavaScript execution to a grinding halt.

Here is an example of using an Angular expression for the same purpose.

<html ng-app="app">
<head>
    <title></title>
</head>
<body ng-controller="Main as vm">
    <span>{{vm.foo}}</span>
    <script src="Scripts/angular.min.js"></script>
    <script>
        (function () {
            'use strict';

            angular.module('app', [])
                .controller('Main', main);                

            function main() {
                var vm = this;
            }
        })();
    </script>
</body>
</html>

Run this in the browser and you see that the UI shows nothing for the undefined property. Change the expression to vm.foo.bar and even the TypeError exception is ignored. Convenient, indeed.

Angular expressions are one of the primary inputs for bindings and directives. This is part of the magic of Angular in the UI. The syntax is clean and generally easy to follow between the view and the controller. In addition to the binding examples already shown, many if not most built-in Angular directives take an expression as input.

<div ng-bind="expression"></div>
<div ng-class="expression"></div>
<div ng-click="expression"></div>
<div ng-focus="expression"></div>
<div ng-if="expression"></div>
<div ng-mousedown="expression"></div>
<!-- and many more...-->

Finally, expressions have a nifty feature called filters. Filters are a way to format the result of an expression for use in the UI. For example if an expression returns a number, the filter is responsible for formatting this number as currency before displaying it in the UI.

Filters are denoted using a pipe character | to the right of an expression followed by the filter name and parameters separated by colons. You can create your own custom filters. Here is a built-in filter example for currency formatting which displays the value $5,147.47.

{{ 12 + 5135.467 | currency:$:2}}

In Closing

This is just a peek into the world of Angular expressions – a feature used by all and misunderstood by many. They give Angular the syntactic ease upon which the framework loosely couples views to controllers.

Angular expressions are deceptively simple, purposefully limit their abuse, and offer delightful benefits to you, the developer. So the next time you open up those double curly braces or the first quote of an ng-bind attribute, write that expression with purpose and care.

2 thoughts on “Angular Expressions”

  1. Hi Aaron!

    I’m making my own e-resume in Angular.JS (to learn the technology) and I’m glad I found your blog among others in Simple Programmer šŸ™‚

    Is there a chance you’ll cover using and creating filters in Angular.JS? That would be very helpfull for me.

    Love your blog. Already subscribed.

    Best wishes,
    Mariusz

Leave a Reply

Your email address will not be published. Required fields are marked *