Using Directives as Data Templates in AngularJS
- Estimated read time: 6 min read
- Written by Chad Campbell on Nov 2nd 2013
AngularJS empowers developers to create custom HTML components. These components are usually HTML elements, attributes, or classes. These custom components can be created with the help of a directive. With this in mind, we can use a directive to create a reusable data template.
A data template is used to setup how a data object looks visually. Data templates are useful when working with a list of items that share a similar visual structure, but have different data. A baseball card is a real world example of a data template.
In this blog post, we'll create a data template named "my-ballcard". To see what the end result of this post will look like, click here. To jumpstart this post, we'll expand on the example used to display groups in AngularJS. Let's start by defining the directive for our ballcard.
Step 1: Define the Directive
When defining a directive, you must choose a name. In this example, we'll use "myBallcard." You may have noticed the absense of the hyphen (-). The reason why is because AngularJS normalizes directive names. We'll go further into this idea after the following code snippet.
The previous directive uses a traditional case-sensitive camelCase name. When referenced declaratively in the HTML DOM, the directive can be referenced by its case-insensitive, dash-delimited name,
To bridge the two worlds, AngularJS takes a custom HTML element's name or attribute and removes any "x-" or "data-" from the beginning. Then, AngularJS converts ':', '-', or '_' delimeters to camelCase. This is how AngularJS looks for the directive's definition. For this reason, the following element names would reference the same directive:
In our example, we gave the ballcard directive a prefix of "my". A prefix helps minimize the risk of name collisions. In addition, it makes code more readable by providing more context. While the latter is more of an opinion, AngularJS allows us to specifically set a directive's declaration style.
AngularJS allows us to set how we want to use a directive. The are four options: HTML element, attribute, class and/or comment. This can be configured through the
restrict property. In the code snippet above, we specifically used 'E', to mark the directive for use as an HTML element. We did this because by default, a directive's
restrict property is set to 'A' for attribute. The other two options are 'C' for class and 'M' for comment. If you want, you can even use multiple options for each directive. Regardless of which options you choose, you still need to consider the template.
Step 2: Define the Template
To move closer to our goal of using directives as data templates, we need to look at using the
templateUrl properties. These properties determine the HTML that will be placed where our directive is used. The
template option is a way to set the HTML inline. For more complex HTML, you may use the
templateUrl property to tell AngularJS to look in a seperate .html file for the template. In our example, we'll use the simpler
template option as highlighted here:
The code above basically says a player's name will appear in bold letters. The player's position and number will appear on the next line. If you inspect the HTML DOM, you may notice that the
my-ballcard elements are written out. You can remove these, and inject only the HTML from your template, by setting the
replace property to
true in the directive definition above.
You may have noticed the use of mustaches (curly braces) in the template. These curly braces are a way to declaratively tell AngularJS to replace this text with some data. That data, and the
playerData variable, are setup in the
Step 3: Setup the Scope
scope property lets us set the data context. By default, a directive will inherit the data context of its closest parent. Based on our previous code snippet, the nearest parent is the
TeamListCtrl. That data context doesn't have the information we want (player
number). To change the data context from the team level to the player level, we first define the scope as shown here.
In this code snippet, we are building the bridge between our directive and the HTML world. The
playerData property is the name of the variable we'll reference in the directive template. The player word sets the name of the attribute we can set in the HTML world. To glue the two worlds, we'll use a little syntactical magic.
The glue is set by a single character. That character can be a '@', '=', or '&'. The at sign (@) sets one-way binding from the source to the target. This is acheived by passing the variable by value. To use two-way binding, the equals sign (=) can be used, which passes the variable by reference. This approach was used in the snippet above. Finally, there's the ampersand (&) which means we should expect an expression. Either way, your character choice must preceed the name of the HTML attribute. Once done, you can set the scope in the HTML world as shown here:
These three steps show how to use a directive as a data template in AngularJS. If you want to see a completed example, you can view it here. The code used for this blog post can pulled from GitHub or downloaded here. If you have any questions or comments related to this post, please leave them in the comments below. If you would like other help from Ecofic, please contact us.