1.Table Of Contents

  1. TOC
  2. Introduction
  3. Building Our Basic AngularJS Directive
  4. Dynamically Loading Data Using $http Service
  5. Demo
  6. Conclusion

2.Introduction

This is the fourth tutorial of the AngularJS directives series using Twitter’s Bootstrap CSS Framework and its JavaScript components. In this part we are going to create a custom modals directive. We are going to build upon the previous tutorials and use AngularJS’s $compile to dynamically load and compile the contents of the modal. This way the HTML we dynamically load in the modal will be parsed for AngularJS directives.

In reality you will rarely need to use $compile as there will almost always be a better way to implement what you need to do. The best example for $compile that comes to my mind is when you need to display the same data in different views that are loaded asynchronously.

3.Building Our Basic AngularJS Directive

Again we’ll start with the basic static directive and build upon it, adding the $http and $compile services.

Basic HTML

The initial HTML is pretty basic – a button and the modal directive:

<div ng-app="customDirectives">
    <div>
        <button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
            Launch demo modal
        </button>
        <div custom-modals modal-id="myModal" modal-title="Our Compiled Modal" modal-src="http://subliminalsources.com/wp-content/uploads/2014/08/modal-example.js"></div>
    </div>
</div>

This time we’ll pass three additional custom attributes:
modal-src – we’ll use this attribute to pass the src of the content.
modal-id – the custom ID we’ll use for this modal(optional).
modal-title – the title that we’ll be applied when the remote template is compiled.

Basic JavaScript Code

Here we’ll use a stripped down version of Bootstrap’s Modal Component

customDirectives = angular.module('customDirectives', []);
customDirectives.directive('customModals', function () {
    return {
        restrict: 'A',
        require: '?ngModel',
        transclude: true,
        scope:{
            ngModel: '='
        },
        template: '<div id="{{modalId}}" class="modal fade">\
  <div class="modal-dialog">\
    <div class="modal-content">\
      <div class="modal-footer">\
        <button type="button" class="btn btn-primary" data-dismiss="modal">Ok</button>\
      </div>\
    </div>\
  </div>\
</div>',
        link: function(scope, el, attrs, transcludeFn){
            scope.modalId = attrs.modalId;
        }
    };
});

angular.module('CustomComponents', ['customDirectives']);

Again nothing special so far. This code we’ll render a button that will trigger empty modal box. Next we are going to load the contents dynamically.

The Result:

4.Dynamically Loading Data Using $http Service

We are going to use the $http service to fetch the template’s contents.

Fetching The Template With $http

For this we’ll use the custom attribute we added above holding the URL to the template. JSFiddle will see my path as foreign domain so for this demo to work I am going to use JSONP to fetch the data. You can always use $http.get or $http.post to get the data when you are using the same domain.

The getContents function is the JSONP wrapper that holds the template. We bind the contents to the modalContents model.

customDirectives = angular.module('customDirectives', []);
customDirectives.directive('customModals', function ($http) {
    return {
        restrict: 'A',
        require: '?ngModel',
        transclude: true,
        scope:{
            ngModel: '='
        },
        template: '<div id="{{modalId}}" class="modal fade">\
  <div class="modal-dialog">\
    <div class="modal-content">\
      <div class="modal-footer">\
        {{modalContents}}\
        <button type="button" class="btn btn-primary" data-dismiss="modal">Ok</button>\
      </div>\
    </div>\
  </div>\
</div>',
        link: function(scope, el, attrs){
            scope.modalId = attrs.modalId;
        
            $http.jsonp(attrs.modalSrc);
        
            getContents = function(data){
                scope.modalContents = data.contents;
            };
    }
}});

angular.module('CustomComponents', ['customDirectives']);

If you run this code you’ll see that the template contents we loaded aren’t parsed as HTML and are displayed as plain text. This is where $compile service comes into play.

Using $compile To Parse HTML

Now, $compile is kinda quirky – to use it properly in a directive we need to append the contents to the element argument of the link function(the element representing the directive element itself). In order to do this I put the whole modal HTML in the remote file.

customDirectives = angular.module('customDirectives', []);
customDirectives.directive('customModals', function ($http, $compile) {
    return {
        restrict: 'A',
        transclude: true,
        scope:{
            ngModel: '='
        },
        template: '',
        link: function(scope, el, attrs){
            scope.modalId = attrs.modalId;
            scope.title = attrs.modalTitle;
        
            $http.jsonp(attrs.modalSrc);
        
            getContents = function(data){
                $compile(data.contents)(scope, function(compliledElement, scope){
                    el.append(compliledElement);
                });
            };
    }
}});

angular.module('CustomComponents', ['customDirectives']);

I pass the directive’s current scope and the clone of the complied element(or list of elements) to the $compile’s transclude function(the second arugment).

In the linking function

el.append(compliledElement);

is the code where I append the compiled element(compliledElement) to the directive’s holder element(el).

5.Demo

Here is the final result with the title we passed to the directive as an attribute.

6.Conclusion

This was the fourth tutorial of the AngularJs Bootstrap Components series, explaining how to use $compile.

This will be the last tutorial in this series for now. With the information in these tutorials you can build any of Bootstrap’s components as AngularJS directives.

Ivan Kovachev
Follow me

Ivan Kovachev

Ivan Kovachev is Technical Team Lead and Senior Web Developer with over six years of professional experience in the field. Ivan also has an unhealthy interest in everything web related.
Ivan Kovachev
Follow me