5 min read

AngularJS 1.3 was released in October 2014 and it brings with it a lot of new and exciting features and performance improvements to the popular JavaScript framework. In this article, we will cover the new features and improvements that make AngularJS even more awesome.

Better Form Handling with ng-model-options

The ng-model-options directive added in version 1.3 allows you to define how model updates are done. You use this directive in combination with ng-model.

Debounce for Delayed Model Updates

In AngularJS 1.2, with every key press, the model value was updated. With version 1.3 and ng-model-options, you can define debounce time in milliseconds, which will delay the model update until the user hasn’t pressed a key in the configured time. This is mainly a performance feature to save $digest cycles that would normally occur after every key press when you don’t use ng-model-options:

<input type="text" ng-model="my.username" ng-model-options="{ debounce: 500 }" />

updateOn – Update the Model on a Defined Event

An alternative to the debounce option inside the ng-model-options directive is updateOn. This updates the model value when the given event name is triggered.

This is also a useful feature for performance reasons.

<input type="text" ng-model="my.username" ng-model-options="{ updateOn: 'blur' }" />

In our example, we only update the model value when the user leaves the form field.

getterSetter – Use getter/setter Functions in ng-model

app.js:

angular.module('myApp', []).controller('MyController', ['$scope', function($scope) {
	var myEmail = '[email protected]';
	$scope.user = {
		email: function email(newEmail) {
			if (angular.isDefined(newEmail)) {
			  myEmail = newEmail;
			}
			return myEmail;
		}
	};
}]);

index.html:

<div ng-app="myApp" ng-controller="MyController">
	current user email: {{ user.email() }}
	<input type="email" ng-model="user.email" ng-model-options="{ getterSetter: true }" />
</div>

When you set getterSetter to true, Angular will treat the referenced model attribute as a getter and setter method. When the function is called with no parameter, it’s a getter call and AngularJS expects that you return the current assigned value.
AngularJS calls the method with one parameter when the model needs to be updated.

New Module – ngMessages

The new ngMessages module provides features for a cleaner error message handling in forms. It’s a feature that is not contained in the core framework and must be loaded via a separate script file.

index.html:

…
<body>
	...
	<script src="angular.js"></script>
	<script src="angular-messages.js"></script>
	<script src="app.js"></script>
</body>

app.js:

// load the ngMessages module as a dependency
angular.module('myApp', ['ngMessages']);

 The first version contains only two directives for error message handling:

<form name="myForm">
	<input type="text" name="myField" ng-model="myModel.field" ng-maxlength="5" required />
	
	<div ng-messages="myForm.myField.$error" ng-messages-multiple>
		<div ng-message="maxlength">
			Your field is too long!
		</div>
		<div ng-message="required">
			This field is required!
		</div>
	</div>
</form>

First, you need a container element that has an “ng-messages” directive with a reference to the $error object of the field you want to show error messages for. The $error object contains all validation errors that currently exist.

Inside the container element, you can use the ng-message directive for every error type that can occur. Elements with this directive are automatically hidden when no validation error for the given type exists.

When you set the “ng-messages-multiple” attribute on the element, you are using the “ng-messages” directive and all validation error messages are displayed at the same time.

Strict-DI Mode

AngularJS provides multiple ways to use the dependency injection mechanism in your application. One way is not safe to use when you minify your JavaScript files. Let’s take a look at this example:

angular.module('myApp', []).controller('MyController', function($scope) {
	$scope.username = 'JohnDoe';
});

This example works perfectly in the browser as long as you do not minify this code with a JavaScript minifier like UglifyJS or Google Closure Compiler. The minified code of this controller might look like this:

angular.module('myApp', []).controller('MyController', function(a) {
	a.username = 'JohnDoe';
});

When you run this code in your browser, you will see that your application is broken. Angular cannot inject the $scope service anymore because the minifier changed the function parameter name.

To prevent this type of bug, you have to use this array syntax:

angular.module('myApp', []).controller('MyController', ['$scope', function($scope) {
	$scope.username = 'JohnDoe';
}]);

When this code is minified by your tool of choice, AngularJS knows what to inject because the provided string ‘$scope’ is not rewritten by the minifier:

angular.module('myApp', []).controller('MyController', ['$scope', function(a) {
	a.username = 'JohnDoe';
}]);

Using the new Strict-DI mode, developers are forced to use the array syntax. An exception is thrown when they don’t use this syntax. To enable the Strict-DI mode, you have to add the ng-strict-di directive to the element that you are using for the ng-app directive:

<html ng-app="myApp" ng-strict-di>
	<head>
	</head>
	<body>
		...
	</body>
</html>

IE8 Browser Support

Angular 1.2 had built-in support for Internet Explorer 8 and up. Now that the global market share of IE8 has dropped and it takes a lot of time and extra code to support the browser, the team decided to drop support for the browser that was released back in 2009.

Summary

This article shows only a few new features added to Angular1.3. To learn about all of the new features, read the changelog file on Github or check out the AngularJS 1.3 migration guide.

About the Author

Sebastian Müller is Senior Software Engineer at adesso AG in Dortmund, Germany. He spends his time building Single Page Applications and is interested in JavaScript Architectures. He can be reached at @Sebamueller on Twitter and as SebastianM on Github.

LEAVE A REPLY

Please enter your comment!
Please enter your name here