Friday, 29 March 2013

AngularJS directives: programmatic

Introduction


In the previous item, we had a first working solution of our panel directive by using the transclude option. However, we have a problem now.  We need to have a way to add a toggle 'button' in the panel header so that we can collapse the contents.
And it needs to be configurable in the directive.

compile function

As described in the introduction, we can also use JavaScript and the compile function to make our DOM structure changes.
AngularJS has by default a JQuery light version so that we can manipulate the DOM structure more easily. However, not all methods of JQuery are supported or works slightly different. So it is a bit trial and error to get some things working.
When JQuery is also loaded, AngularJS uses the full version.
This is the code that I call

var myPanel = {
    create: function (element) {
        element.addClass('pui-panel ').contents().wrap('<div class="pui-panel-content" />');
        var title = element.attr('title');

        element.prepend('<div class="pui-panel-titlebar "><span class="ui-panel-title">'
                + title + '</span></div>').removeAttr('title');

    }
};


The above code is quit easy to understand I guess.  It is a simplified version without styling. Adding the CSS classes you can create a nicer user experience. The 2 versions are available in the github repository.
We add a CSS class to the element itself, and wrap the contents of the element in another div with a CSS class pui-panel-content. This is a preparation for the next steps where we need to collapse the contents.
In the last step we add a div for the panel title header.

The directive becomes then very small

directive('myDir3', function version3() {
        return {
            restrict: 'A'
            , compile: function (element, attrs) {
                myPanel.create(element);
            }
        };


If you run the page, you have the same result as we had with the template and transclude solution explained in the previous blog item.  The advantage we now have is that we now can add an options parameter to our call and have conditional behaviour.

Expressions compatible


The above solution still works when you use an AngularJS expression for the title attribute and when you have a more dynamic content, with expressions or even other directives.
In the example, you can try this out by changing the value in the input fields and see the corresponding parts of the panel widget change along.

The code of the example at Github is updated to include the code described in this blog item.

Conclusion


Although it is technically possible to set the template based on some options specified, it is most of the time much more clear and flexible to write JQuery alike DOM manipulation. It also opens the possibility to integrate third party widgets like I did with AngularPrime and PrimeUI in this way.

In the next item we will cover the optional configuration to have a collapse functionality.

1 comment: