Angular: Basic Custom Directives using template and templateUrl

Custom directives in AngularJS allow to create your own element or attribute tags in order to accomplish specific goals you may have. As a general rule, custom element directives should be used to manipulate the view in some sort of fashion while custom attribute directives should be used to bolster or enhance a current element (such as a validation attribute in a login/registration form).

In order to create a directive the directive() function needs to be called on an Angular module. This is done simply like so:

(function(){

angular
 .module('app', [])
 
 .controller('mainController', function(){
 
 })
 
 .directive('myDirective', function(){
     return{
         template: "This is my directive"
     }
 })
 
})()

This is a basic directive that will simply display the defined template. The way the directive is currently configured, it can be used either as an element or an attribute because we have restricted it’s use as just an element or just an attribute.

in the HTML, using the directive as either attribute or element will create the same results.

2015-04-12_Directive

One thing to notice in the way that the directive is being used is that the naming convention in the HTML is different from how it was defined in the directive function. Camel-Casing the directive name in the js file translates into either using dashes ( – ) and/or semicolons ( : ) between the words in the HTML. So the directive could have been written <my:directive> or if the name was longer, like¬†thisIsMyDirective, it could have been something like <this:is-my:directive>… it would all rendered the same. It’s also no case-sensitive in the HTML.

Now if we wanted to restrict the use of the directive into only being an element, we could simply add the restrict keyword to the directives return object like so:

 .directive('myDirective', function(){
     return{
         restrict: 'E',
         template: "This is my directive"
     }
 })

Doing so would make the use of the directive attribute do nothing, and the image from above would no longer display the second ‘This is my directive’ in the HTML… In order to restrict the use of the directive to an attribute, ‘A’ would be used instead of ‘E’ and the reverse would be done in the HTML, the first ‘This is my directive’ would no longer show and the second would.

When using custom directives as elements, using the template keyword can become cumbersome because you may very well end up with this huge block of HTML code in your JS file… and no one wants that. The best thing to do, would be use to the templateUrl keyword and inject in a template of an external HTML page. I’ve created an external file called myDirectiveTemplate.html with the following code:

<div class="col-lg-4">
 <div class="panel panel-success">
   <div class="panel-heading">
     <p>Some Stuff here</p>
    </div>
    <div class="panel-body">
      <p>Some stuff there</p>
    </div>
 </div>
</div>

This HTML file can now be used with the directive and injected in via templateUrl like so:

2015-04-12_Directive_templateUrl

Now, we can expand the use of the directive as it is by improving upon the template in which it’s injecting. For Example: let’s say we wanted to change the header and content of the panels by using expressions and using a controller to control the data.

If we utilize our controller to hold an array of objects, we can use ng-repeat to create multiple panels with very minimal code having to be used in the view that’s actually using the directive.

The controller would look something like this:

 .controller('mainController', function(){
 var vm = this;
 vm.panels = [
   {
     Heading: "Panel1",
     Body: "The body of Panel1"
   },
   {
     Heading: "Panel2",
     Body: "The body of Panel2"
   },
   {
     Heading: "Panel3",
     Body: "The body of Panel3"
   }
  ]
 })

Then the template is updated to use expressions like so:

<div class="col-lg-4">
 <div class="panel panel-success">
   <div class="panel-heading">
     <p>{{panel.Heading}}</p>
   </div>
   <div class="panel-body">
     <p>{{panel.Body}}</p>
   </div>
 </div>
</div>

Finally the view itself is updated with the ng-repeat in order to run through each object in the panels array:

2015-04-12_Directive_UsingControllerAndNgRepeat

This is a pretty decent improvement over something that would look like this instead:

2015-04-12_Directive_UsingControllerAndNgRepeatWithoutDirective

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s