Skip to main content
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Seth Bienek
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Seth Bienek@sethbienek )

Watching Object Literal Expressions In AngularJS

By on

The other day, when I created a pixel-based version of ngStyle, I did something in AngularJS that I had never done before: I watched an expression that consisted of an Object literal. This works just like watching rgular $scope references; but, it has a few caveats that I thought I would share.

Run this demo in my JavaScript Demos project on GitHub.

I don't think there is any reason that I would ever have to watch an object literal expression inside of a Controller or a Service; but, in a Directive it makes sense. It allows the user to define an object in an Element attribute - think ngClass and ngStyle - which provides a good deal of flexibility and readability.

In my experiments, the major caveat with watching an object literal expression is that AngularJS creates a new object every time the $watch() expression is checked. This means that you can't use reference-based equality in your $watch() configuration. If you do, the newValue will always be different than the oldValue and the $digest phase will never end (without error). Instead, when watching an object literal expression, you have to use deep-object-equality. This compares the newValue and the oldValue based on the actual structure of the object and not just on its reference.

To see this in action, take a look at this simple demo where I define a $watch() on an object literal expression. Note that I am passing in "true" as the third argument of the $watch() configuration - this tells AngularJS to use that deep-object-equality.

<!doctype html>
<html ng-app="Demo">
	<meta charset="utf-8" />

		Watching Object Literal Expressions In AngularJS
<body ng-controller="AppController">

		Watching Object Literal Expressions In AngularJS

	<!-- Load scripts. -->
	<script type="text/javascript" src="../../vendor/jquery/jquery-2.1.0.min.js"></script>
	<script type="text/javascript" src="../../vendor/angularjs/angular-1.2.4.min.js"></script>
	<script type="text/javascript">

		// Create an application module for our demo.
		var app = angular.module( "Demo", [] );

		// -------------------------------------------------- //
		// -------------------------------------------------- //

		// I control the root of the application.
			function( $scope, $parse ) {

				$scope.friend = {
					id: 4,
					name: "Heather"

				// When we parse an AngularJS expression, we get back a function that
				// will evaluate the given expression in the context of a given $scope.
				var getter = $parse( "{ name: }" );

				// Get the result twice.
				var a = getter( $scope );
				var b = getter( $scope );

				// Check to see if evaluating the AngularJS expression above returns a
				// new object each time.
				// --
				// HINT: It does (return a new object each time).
				console.log( "Objects are equal:", ( a === b ) );

				// Since a new object is returned each time the Object Expression is
				// evaluated by AngularJS, we havd to use DEEP object equality.
				// Otherwise, the object reference will be different on EACH $digest
				// iteration, which will cause the digest to run forever (or rather,
				// to error out).
					"{ name: }",
					function( newValue, oldValue ) {

						console.log( "Watch:", );


					// Deep object equality.




I said that you would probably never run this in a Controller; but, I'm using a controller here just to keep the code simple. And, when we run the above code, we get the following console output:

Objects are equal: false
Watch: Heather

As you can see, subsequent calls to the $parse-based "getter" return a new object reference each time. But, the deep-object-equality allows our $watch() handler to ben called only once since the "value" of the object never changes.

The nice thing about passing an object literal expression into a Directive is that it allows you to consolidate all of the values related to your directive. This is definitely something that I want to explore a bit further.

Want to use code from this post? Check out the license.

Reader Comments


Does this still apply if you use a function as the first argument to the $watch function?

function(){ return; },
function( newValue, oldValue ) {



When you pass in a function as the watch "expression", the function will get called on *every* digest; however, your watch handler (the function that gets passed the new/old values) will only get invoked when the value you *return* from your watch expression function changes. So, to answer your question, No - this does not apply for your case. In the example you have, "" will be evaluated and return on each digest; but, unless the name actually changes, your callback handler won't be invoked.