AngularJS–Part 6, Templates

Introduction

This is a series of posts about AngularJS and our experiences with it while migrating the client of a complex enterprise application from Silverlight to HTML5/CSS/JavaScript using AngularJS as a framework. Since the migration is a very ambitious undertaken I want to try to chop the overall problem space in much smaller pieces that can be swallowed and digested much more easily by any member of my team. So far I have published the following posts in this series

In Angular when we talk of a template we really mean the view with the HTML enriched by the various Angular directives and the markup used for data binding (the expressions in double curly braces {{ }}). We can of course go a step further and not only regard a whole HTML document as a template but also any HTML fragment, often called partials. In this post whenever I’m talking about templates I refer to the latter.

A simple sample

Whenever we want to display a list of things on a page we can use the ng-repeat directive to do so. Let’s assume we have a list of persons that we want to display. We first define a controller that provides a (pre-canned) list of persons on its $scope. Normally we would get this list of persons from the backend by using e.g. the $http service, but here we want to keep it simple and concentrate exclusively on the client side part. Now lets put this code in a file called app.js

image

To display the full name of every person in a simple list we can use this template

image

Just to repeat the important elements:

  • We need the ng-app directive somewhere in the HTML DOM to bootstrap Angular. Everything nested inside the element containing the ng-app directive is managed by Angular, everything outside is NOT. It is very important to remember this – everything that is defined outside the scope of the ng-app directive is ignored by Angular; in our case this would be the whole header of the HTML document.
  • We reference the JavaScript files that we need at the bottom of the body tag to allow the browser to render the DOM before it loads the JavaScript files. Loading those files is a blocking operation. Another important best practice is to always use the non-minified versions of the files during development otherwise debugging becomes a nightmare if not impossible. Of course we should not forget to reference the minified versions of our JavaScript files once we are ready to move our app into production.
  • We use the ng-controller directive to define the HTML fragment which shall be managed by our controller PersonCtrl. Again, here the controller manages everything nested inside the element containing the ng-controller directive.
  • Whenever we want to display a list of some sort based on a collection of things defined on the $scope in our controller we can use the ng-repeat directive. The syntax of the expression in the ng-repeat directive is of type “thing in things” or in our case “person in persons”. The ng-repeat directive basically iterates over all items of the collection and for each item creates a copy of the HTML element on which it is defined. The respective item “becomes the scope” of each of the repeated elements. We can then use data binding to display values of each item in our view. In our sample the fragment
    image
    is repeated 5 times

The result of the above

image

Static templates

In a very simple application what we did so far is totally ok and sufficient. If we are looking at more realistic and complex samples we might want to separate structure and layout of the list. Instead of defining what should be output of a given person and how it should be displayed in place we might want to extract this part from the main view and place it somewhere else, maybe in its own file. But before we use separate files we can also just define templates (remember I use the word template as a synonym for HTML fragment) in a different area of the file. Angular gives us the option to define named templates in a special script tag. There are three important boundary conditions that must be fulfilled

  • the script tag must be defined inside the scope of the ng-app directive otherwise it and its content is ignored by Angular.
  • the type attribute of the script tag must be “text/ng-template”
  • the script tag must contain an id attribute with a unique value.

To use the template defined within a script tag we add an ng-include directive to the parent element whose value is the ID of the template. Thus if the ID of the template is person.html then the directive must be

image

Important: Please not the single quotes around person.html. The value of the ng-include is an expression and to indicate to Angular that person.html is a string value we need to put those single quotes around it.

That said, our view now looks like this

image

Structural HTML has been separated from specific layout parts. If you refresh the page in the browser after these changes the output should look exactly the same way as before. Although here in this very simple sample it is not really evident what the benefit should be, just believe me that the true beauty of  this principle comes to shine in more complex situations.

Note that all the templates that you define with the technique shown above are stored in the Angular template cache and they are available to you at any time via the $templateCache service.

If we have more and more different templates we want to use and the templates become more and more complex it makes sense to store them in their own individual files. Let’s just do that and extend our sample. On our view we output a second list of the same persons but this time we are using a template person2.html stored as a file in a subfolder called templates. The HTML we add to our main view (index.html) looks like this

image

And the content of the file person2.html might look like this (to not use the very same boring layout as in the above template)

image

Note that I use a CSS class person which is defined as

image

The above definition resides in a file app.css that I reference in the header of my index.html

image

Finally when refreshing the browser we get this result

image

The advantage is now that I can go and significantly change the layout of each person item in the list without having to touch the index.html view. Let’s just do this for fun and add an icon to each person which is depending on the gender of the person. To make things simple I just went quickly on Bing and searched for small male and female symbols and stored them as M.jpeg and F.jpeg respectively in the same folder as the index.html. Then we can change the template person2.html as follows

image

Please not the usage of the ng-src directive in the img tag. It allows me to use data binding. In my case I use the content of the gender property on our model to determine which image to use. For a nicer looking list I also fix the width of the image to 25 pixels. The result of which is

image

Dynamic templates

What if we want to display a list of items where we need a different template for each of the items? How can we handle that? Let’s take the sample of a (simple) questionnaire to analyze this problem. A questionnaire is a document that has a series of questions where the user is required to fill in answers for each question. The type of question determine what kind of answer the user has to provide. Is it a plain text, a numeric, a date type or multiple choice answer? Certainly you can imagine many more types or categories of answers. We want to show the questionnaire as a list of questions and have each question display the answer part according to the type or category of question.

Let’s start with the controller where we define on its $scope a simple pre-canned questionnaire.

image

Now let’s define the HTML that outputs the questionnaire as a series of div tags. For a first iteration we only want to print the question number, type and text.

image

The CSS is

image

Nothing spectacular so far, but at least we get the expected result.

image

Now comes the interesting part. To each of the questions we want to define an area where the user can answer the corresponding question and as we have noted above each question has a different kind of answer layout, depending on the type of question. Let’s realize this by defining a template per question type. We will create a file per template and will name the file like the type of the question, e.g. number.html, text.html, etc.

text.html

image

number.html

image

date.html

image

singleOption.html

image

multiOption.html

image

And we need to modify the main template slightly too

image

Note specifically how we leverage the fact that the ng-include value is interpreted as expression by Angular and as such we can combine data binding (question.type) and string concatenation to generate the URL to the template to load.

The CSS class answer is defined as follows

image

Once we have defined all these templates the output in the browser is as follows

image

As expected each question has its own individual answer layout.

In a real application each template would probably have its own controller containing the workflow logic for the appropriate question; but this lies outside of the scope of this post which is already pretty long.

Recursive templates

Sometimes we want to display templates that in turn reference other templates which again might reference more templates. These are called recursive templates. A very good sample for this is a tree where a root node has children which in turn are nodes and have children and so on. How would we display such a tree? If we hardcode such a tree in HTML it could look like this

image

That is, just a series of nested unordered list which in the browser are displayed like this

image

It is evident that this does not work for any arbitrary tree structure e.g. loaded from a backend server. Luckily Angular provides us with the possibility to define recursive templates. Let’s just start and see how to do that. First we define a new TreeCtrl controller having a pre-canned tree structure defined on its $scope.

image

Let’s now do a first implementation of the view. We add the following HTML snippet to the index.html

image

This of course will only show us the list of parents since we have not yet defined any recursion. To do that we need to use templates. We will define the template directly inside the index.html by using the special script tag

image

After this modification the result is still the same but now we can start to extend our new node template and add recursion to it. We do not only want to display the name of the current node but also a nested list of all children of the current node. Nothing easier than that

image

Note how in the nested list the ng-repeat directive is used to iterate over all children of the current node and how the ng-include directive is used to self reference the template. And the output is as expected

image

Conclusions

Templates come in very handy whenever we want to separate pure structural or semantic layout from more specific layout of certain UI fragments. In this regard using templates helps us in adhering to the single responsibility principle.

In this post I have discussed in detail three categories of templates – static, recursive and dynamic templates. We make heavy use of each category in our complex enterprise solution. In this post I have only scratched on the surface on what is possible when using templates as supported by Angular.

The code to this series can be found on GitHub.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Gabriel Schenker

Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 12 years as an independent consultant, trainer, and mentor mainly on the .NET platform. He is currently working as chief software architect in a mid-size US company based in Austin TX providing software and services to the pharmaceutical industry as well as to many well-known hospitals and universities throughout the US and in many other countries around the world. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process. Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.
This entry was posted in AngularJS, How To, introduction. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Lorenzo Melato

    Gabriel, thanks for this great introduction serie, we are approaching AngularJS these days and I have found your tutorial really useful!

  • stacy murray

    This is great! Never thought about doing recursion like this on the client.

    “… I have only scratched on the surface on what is possible when using templates as supported by Angular.”

    I hope you would consider doing a follow-up post on templates so we can discover more real-world possibilities on the client. After all, delivering a great user experience is where the buck stops. If that’s not right, nothing else really matters.

  • Rod McBride

    Great post Gabriel! I’m looking at refactoring an existing Web application using AngularJS and found this introduction to Templates quite helpful. Thanks for sharing and keep up the great work.

  • jlamande

    Hi,
    A nice and clear one not mixing subjects.
    A question about creating separate files for templates.
    Does it result in an HTTP request for each template ?
    I mean : is it a gain in favor of maintenability at the potential cost of performance ?
    In a bigger app, will all templates be preloaded by default, I think should be to avoid display latencies with on-demand loading ?
    Thx