Subliminal Sources

Adventures in development

February 11th, 2014

AngularJS-Shield-large

1.Table Of Contents

  1. TOC
  2. Introduction
  3. Building Our Basic AngularJS Directive
  4. Bootstrap Popover Functionality
  5. Demo
  6. Conclusion

2.Introduction

This is the first of a series of tutorials I am going to write about building AngularJS UI widgets using Twitter’s Bootstrap CSS framework. In this first part we are going to build custom popover(more advanced popup) directive. The aim of these tutorials is to show you how to implement different UI  widgets ‘the Angular way’, which means will keep all of our DOM operations in the directive. These series will require from the reader to have basic AngularJS knowledge. AngularJS comes with pretty big list of built-in directives. So I wont go into much detail about AngularJS directives and move on to building the popover(a little bit more advanced popup).

There are a few ways to declare a directive in the html, but using the attribute approach is the one I preffer and also it seems most consistent with HTML5 spec(and works in older IE versions):

<span custom-popover></span>

When this code is parsed angular will search for customPopover directive and apply it to the element. Now we need to build that directive.

3.Building Our Basic AngularJS Directive

Folder Structure

Which is the best way to structure AngularJS project is widely discussed topic so I wont go into much detail how you should structure yours and focus on the folder structure I use for my directives. I like to keep my directives in separate directives folder in my angular project folder and write their code in directive.js file. I keep directives in one module, but they can be separated in groups and injected when needed so Angular wont have to parse code that is not used. I put my templates in html files in templates folder in my directives folder.

AngularProjectFolder
|
\directives
 |
 \directives.js
 \templates
  |
   \directiveTemplate.html
   \directiveTemplate2.html

AngularJS Directive JavaScript Code

The basic code for our directive will look like this:
directives.js:

customDirectives = angular.module('customDirectives', []);
customDirectives.directive('customPopover', function(){
    return {
	restrict: 'A',
	template: template: '<span>Label</span>',
	link: function (scope, el, attrs) {
            console.log("Popover Directive Loaded");
	}
    };
});
The Restrict option

Restrict option specifies how the directive is called in the HMTL.

A - <div custom-popover></div>
C - <div class="custom-popover"></div>
E - <custom-popover></custom-popover>
M - <!-- directive: custom-popover -->

However using the E option wont work in older browser versions that don’t support custom elements. You can also combine the values and use multiple ways for calling the directive, although I’d advise you to stick to one option and be consistent with it.

{ restrict: 'AE' }
Template And TemplateUrl

The template option defines the HTML code that will replace the content of the element(if any) calling the directive. In this case:

<span custom-popover>CONTENT THAT WILL BE REPLACED</span>

With the transclude option we can use the content of the element with the ngTransclude AngularJS directive, but we will cover this in some of the next tutorials.

If you want to keep you template code in separate file you can use the templateUrl option and provide URL to HTML file. Keep in mind that it follows the same restrictions as ngInclude.

Link

The link option is used when the directive will do DOM manipulations. It usually takes 3-4 arguments:
scope – AngularJS scope object used by the directive
el – jqLite element that matches the element calling the directive.
attrs – It’s an object containing key-value pairs of all of the attributes of the element calling the directive.

4.Bootstrap Popover Functionality

In this form our directive will only show the text ‘Label’ in the wrapping element calling the directive, so we have to add the popover initialization code in our link function. We will also add 3 additional custom attributes to the HTML element matching the directive.

<span custom-popover popover-html="Some Popover Text" popover-placement="bottom" popover-label="Label"></span>

popover-html – will contain the HTML or plain text content of the popover.
popover-placement – will be used to pass the placement option for the popover. Bootstrap requires one of the following values – top | bottom | left | right | auto.
popover-label – this one we’ll use to set custom label for the element calling the popup.

To make the attributes values visible in the template we need to pass them to the scope argument of the link function.

scope.label = attrs.popoverLabel;

Then we need to initialize the popover functionality and pass some options to the popover widget.

customDirectives = angular.module('customDirectives', []);
customDirectives.directive('customPopover', function () {
    return {
        restrict: 'A',
        template: '<span>{{label}}</span>',
        link: function (scope, el, attrs) {
            scope.label = attrs.popoverLabel;

            $(el).popover({
                trigger: 'click',
                html: true,
                content: attrs.popoverHtml,
                placement: attrs.popoverPlacement
            });
        }
    };
});

You can find the options for the popover here.

5.Demo

Here is a jsFiddle demo of the popover directive:

6.Conclusion

In this first tutorial of the AngularJs Bootstrap Components serires I’ve showed you how to build simple popover directive. You can use this basic code and build upon it more customized directives with additional custom attributes and implement more of the options provided by Bootstrap’s popover widget, and you could also customize the looks of the popover with some custom css styles.

In the next tutorial of the series I’ll show you how to build Collapse(Accordion) Directive based on Bootstrap’s Collapse JS widget

If you find this information useful, please upvote, share and comment.
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.
Follow me
flattr this!

Tags:

  • Pingback: HTML5 | Pearltrees

  • Tim

    The real question is how to have dynamic binding on the content of the popover?

    • Ivan Kovachev

      Hey, Tim

      Thank you for your response. I’ll cover dynamic data bindings in the next tutorial(which will be ready this week) of the series, but generally its done with the ‘scope’ and in some cases ‘require’ options. If you can’t wait for the next tutorial check these options in the AngularJS docs http://docs.angularjs.org/guide/directive

  • Pingback: Building Custom AngularJS UI Component Directives « Subliminal Sources

  • Pingback: Building AngularJS Bootstrap Collapse(Accordion) Directive Tutorial

  • miliu99 .

    Thanks for the directive. This is exactly what I’m looking for because using template is too complated to me. It works as is. However, when I change the trigger from click to mouseenter, it doesn’t work anymore. Any idea? How to fix it?

    • Ivan Kovachev

      Hey thanks for reading. The directive relies on Twitter’s Bootstrap JavaScript Components so the accepted options for trigger are “click | hover | focus | manual“. In your case you should use with “hover“.

      More info here – http://getbootstrap.com/javascript/#popovers

      • miliu99 .

        This is great. Thank you so much!

  • Pingback: AngularJS-Learning | Nisar Khan

  • benlagrone

    Is there a way to do this ‘the Angular way’? ie. not using jQuery. In the documentation I read (and it stuck with me), “If you find yourself needing to use jQuery with Angular, then you are doing it wrong”. But I’m stumped; if Event-Driven is wrong, then how do you make a tooltip on a custom event?

    • Ivan Kovachev

      Hey, first sorry for the reaaaaaaly late comment.

      Angular actually uses jQlite which is a jQuery subset, but bootstrap is build on jQuery so that’s why It’s used here. Also if you have jQuery included Angular will acutally use it – you can read more about this here https://docs.angularjs.org/misc/faq.

      Their main point is to avoid DOM manipulations in the controllers and do them in the directives. Event-Driven is not wrong they even have directives that implement events like ng-click, ng-change, etc..

      Again sorry for the late answer and I hope this helps.

  • Pingback: Building AngularJS Bootstrap Popover Directive ...