Templates in AngularJS are quite powerful, but just because something can be done in the template doesn’t mean you should do it there. The separation between controller and template can be vague in Angular, which is why I have a couple of guidelines which I consider to be best practices in any Angular project.

One of those rules of thumb is: Don’t do in the template what can be done elsewhere.

In this post, I will go over the different symptoms of template overuse and why it can be problematic.

Template Overuse Symptoms

Template Overuse (noun): Performing work in the template that will be better placed somewhere else.

ng-click

A popular example is ng-click abuse:

1 2 3 <button ng-click= "$ctrl.validate() && $ctrl.submit()" > Submit <button>

As you can see, the ng-click handler is first making sure that the form is valid before actually calling the submit operation.

This extra logic is misplaced.

A similar, yet different, example is:

1 <button ng-click= "$ctrl.counter = 0" > Reset </button>

As a guideline, template event handlers should trigger functions on the controller, and not any other expression/statement (e.g. the above would be ng-click="$ctrl.reset()" ).

This goes the same for similar directives, such as ng-submit , etc.

ng-init

This, for some reason beyond me, is not an uncommon sight:

1 <div ng-init= "$ctrl.setup()" >

In case you’re not aware of it, ng-init simply runs the code given to it when the template initializes. Its valid use cases are so rare, even the documentation warns against using it.

And yet, a GitHub search comes up with 785K+ hits at the time of this writing.

There’s a good place to initialize stuff: the controller’s $onInit hook!

Underusing CSS

All the power we get from templates might make it easy to forget that not all visual logic has to be done inside them. A good example is using ng-if or ng-class for targeting special cases that can be handled in CSS, like special casing the first element in a list, or coloring every other row, like I’ve shown here.

Forgetting the Basics

I see too many developers reinventing the wheel instead of making use of the power of the web.

Consider the first example here, which showed ng-click="$ctrl.validate() && $ctrl.submit()" . There’s a known mechanism for preventing actions on buttons in case the form state is invalid, which is setting those buttons to be disabled . This can be done by using Angular’s validators, or even simply by using ng-disabled :

1 2 3 <button ng-disabled= "!$ctrl.validate()" ng-click= "$ctrl.submit()" > Submit </button>

Why is Overuse Bad?

First, having extra logic in the template makes it harder to refactor code at a later point. I’ve yet to come across the perfect IDE that makes refactoring templates as smooth as refactoring JavaScript code. If that’s the case, I opt for the style that makes refactoring easier.

Further, it’s very easy for templates to contain a bunch of dense expressions and overly long ng-if conditions. These in turn make code maintenance a PITA. Templates should be easy to change when view requirements change, and are best when they make it easy to understand and visualize what is happening on screen. The more code in your templates, the harder they become to follow.

Also, logic in template also makes it harder to properly unit test controllers. For example, if the template contains an ng-init hook, then usually the test would also have to invoke whatever expression the ng-init is calling.

Essentially, all these reasons boil down to complicated templates making code maintenance harder in the long term. Making a point of keeping templates succinct will make for a codebase that everyone will be happier working on.

Fixing Overuse

To repeat, the basic guidelines you should strive to follow are:

Don’t do in the template what can be done elsewere. Template event handlers should trigger functions. Remember the basics, like CSS and HTML form validation. Don’t use ng-init . Just don’t.