Make data table reusable

In the previous post we checked the project itself behind this blog post series and the library that we chose as a base of our implementation.

Our next task with the base library in our hand was to place the dataTables inside our Angular.js app. This post will be about the steps to achive this.

The best way to create a reusable component in angular is to create a directive. So I wrapped the dataTables implementation inside a directive.

Let’s see how!

The directive

angular.module('angularTableApp')
    .directive('myDataTable', function ($parse) {
        'use strict';

        return {
            template: '<table class="display table table-striped table-hover" id="my-data-table"></table>',

            link: function postLink(scope, element, attrs) {

			…

			$("#my-data-table").dataTable(...);
			…	

		}
	};
);

I will not explain all the settings of an angular directive in this post because I plan to write posts about angular.js and about directives as well.
( But if you have never heard about directives you can check the official page. )

There are parts that we need to know at this point:

  • We have an angular module, the main module with the name ‘angularTableApp’ and a directive is a reusable UI elment we can define
  • ‘myDataTable’ is the name of the directive → my-data-table will be the name of the directive in HTML
  • This directive will be available as an attribute of a HTML element.
  • If a div has our attribute, angular will build the content of the template inside the div.
  • In the ‘template’ I defined a HTML table with the Twitter Bootstrap classes and with the id to identify it. (Instead of id you can use class to have more table on one page.)
  • The div with the id ‘customHeader’ is a placeholder for the custom header controls.
  • In the ‘link’ function we are after the compile phase. We have all the DOM elements in place – the content of the template is inside the div – and we can manipulate them.

This ‘link’ function has three parameters

  • ‘scope’ – The scope from the controller
  • ‘element’ – The element on which the my-data-table attribute is
  • ‘attrs’ – The attrs gives us all the other attributes on the container div

The HTML part

We need to mark the HTML element with the attribute of the directive – ‘my-data-table’ – and we can add other attributes which we want to use later inside the directive:

<div my-data-table 
		my-source="dataSource" 
		refresh="refresh(data)" 
		header="headerControls" 				//optional
		page-sizes="pageSizes" 					//optional
        sorting-properties="sortingProperties"  //optional
        hiding-properties="hidingProperties" 	//optional
        delete-row="deleteRow(item)" 			//optional
        edit-row="editRow(item)" 				//optional
        select-row="select(item)" 				//optional
        >
</div>

‘my-source’ and ‘refresh’ are required parts of the data table. The others are only optional tags.

  • ‘my-source’ is the data source of the actual page of the table.
  • ‘refresh’ is the callback to react on the change of the table queries.

Inside the directive

On the script side, inside the directive’s link function we will use now only two from the paramaters.

We need attrs to to reach all the optional parameters of the container element and the scope to get the bound values this attributes from the actual scope of the page.

We can bind functions and properties of the actual scope as attributes of the HTML element.
On the directive’s side there are two different method to get the bound items correctly.
One to get the functions and one to get the properties.

How to handle bound functions inside the directive

We can get the name of the function from the attributes and after that we need to call the $parse function of angular with the name of the function.

var refreshHandler = $parse(attrs.refresh);

‘$parse’ can be requested from angular and get through dependency injection

angular.module('angularTableApp').directive('myDataTable', function ($parse) { … }

After parse you get the function itself and you can call it in an angular specified way.

scope.$apply(function () {

                        refreshHandler({data: conditions}, scope, { $event: event });
                    }); 

Tip 1 – Check noop
If you try to parse function by the attribute name but the user has not defined the attribute – in this case ‘refresh’ – it will not work.
It will give you an empty function with the name ‘noop’. (Angular built-in function.)
If it’s a ‘noop’ function and you call it like it would be your function, nothing will happen. It will not throw an exception but will not do what you request from it.

To avoid this malfunctioning you can check the result of the parse:

if (refreshHandler != angular.noop) {/*activate the option to call this and/or do the call*/}

Tip 2 – How to use parameters
If you want to add parameters to the function, they have to be defined in parse time.
Which means that in HTML you need to write refresh=”refresh(data)”.

In this case you can call the function later with the ‘data’ parameter.
If you write in html only refresh=”refresh()” it will not handle the parameter. It will not throw an exception. It will only ignore the parameter.

If you registered the parameter you can pass it to the function and use it in the controller.

Tip 3 – The way of function call
The from attribute parsed functions are outside the angular environment / angular loop so we can’t just call them as an original function of the angular scope.
We need to call them inside the apply method of the angular’s scope.

scope.$apply(function () {

                        refreshHandler({data: conditions}, scope, { $event: event });
                    }); 

Calling the function requires to pass the scope and to set the $event to it. (The way of Angular.js)

How to handle bound properties inside the directive

It is much easier because we have the scope of the controller. (Remember the scope is one of the parameters of our ‘link’ function.)

We only need to index the scope with the property name.

	scope[attrs.header]

The property name what we want to reach comes from the the other parameter of the function, from ‘attrs’.
That’s it!

Summary

These were the steps of the integration. Now we have the data table as a reusable component to use it inside an Angular.js app. We created the channel to communicate between our directive and the page’s scope.
We can hide the implementation of all the features that we want to add to our table inside this directive and we can publish to the user of our table a nice API.

In the next post we will check how to fill the table with features and I will show the implementation of the features from the sample app.

Advertisements

3 thoughts on “Make data table reusable

  1. Pingback: Data table in angular | My Journey InTo JavaScript

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