AngularJS Directive for table header

14,862

Solution 1

What you need to do is for each element using your directive providing both an order and the current order (the one from your controller).

BTW I think your directive will be a better match as an attribute and not a tag. You can check the following code :

angular.module('myApp', []).directive("sort", function() {
return {
    restrict: 'A',
    transclude: true,
    template : 
      '<a ng-click="onClick()">'+
        '<span ng-transclude></span>'+ 
        '<i class="glyphicon" ng-class="{\'glyphicon-sort-by-alphabet\' : order === by && !reverse,  \'glyphicon-sort-by-alphabet-alt\' : order===by && reverse}"></i>'+
      '</a>',
    scope: {
      order: '=',
      by: '=',
      reverse : '='
    },
    link: function(scope, element, attrs) {
      scope.onClick = function () {
        if( scope.order === scope.by ) {
           scope.reverse = !scope.reverse 
        } else {
          scope.by = scope.order ;
          scope.reverse = false; 
        }
      }
    }
}
});

And the plunker that goes with it : http://plnkr.co/edit/P4cAm2AUGG36nejSjOpY?p=preview

The directive is used as such :

<thead>
  <tr>
    <th sort by="order" reverse="reverse" order="'name'">Name</th>
    <th>Phone</th>
    <th sort by="order" reverse="reverse" order="'age'">Age</th>        
  </tr>
</thead>

Solution 2

Unless you are intent on writing your own directive, you might consider looking at what is available. ngmodules.org shows some directives that are already set up for table headers.

Here are a couple options with some sample code to give you a feel for both. They both look to be developed and very customizable.

ngTable

ngTable snapshot

angular.module('main', ['ngTable'])
.controller('DemoCtrl', function($scope, $filter, ngTableParams) {
    var data = [{name: "Moroni", age: 50}, ... ]

    $scope.tableParams = new ngTableParams({
        page: 1,            // show first page
        count: 10,          // count per page
        sorting: {
            name: 'asc'     // initial sorting
        }
    }, {
        total: data.length, // length of data
        getData: function($defer, params) {
            // use build-in angular filter
            var orderedData = params.sorting() ?
                                $filter('orderBy')(data, params.orderBy()) :
                                data;

            $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
        }
    });
});

UI Grid

UI Grid snapshot

angular.module('app', ['ngAnimate', 'ui.grid'])
.controller('MainCtrl', function ($scope) {
  $scope.gridOptions1 = {
    enableSorting: true,
    columnDefs: [
      { field: 'name' },
      { field: 'gender' },
      { field: 'company', enableSorting: false }
    ],
    onRegisterApi: function (gridApi) {
      $scope.grid1Api = gridApi;
    }
  };
});
Share:
14,862

Related videos on Youtube

Brian
Author by

Brian

Working at JAMF software in the development operations group.

Updated on September 15, 2022

Comments

  • Brian
    Brian over 1 year

    I am trying to write a directive to deal with changing an icon class for table headers. What I would like is (what I believe anyway) the standard way of dealing with sorting by table headers. The directive would add a link element and upon a user's click sort by desc and change the icon to desc, upon click again sort by asc and once again the the icon. Here is what I have so far, but I am now at a loss for how to deal with the icon class as well as resetting other elements on the same table but outside of the directive's scope. Any help would be great!

    angular.directive("tableHeaders", function() {
    return {
        restrict: 'E',
        scope: {},
        template:'<i class="glyphicon glyphicon-filter"></i>',
        link: function(scope, element, attrs) {
            attrs.class = 'glyphicon glyphicon-sort-by-alphabet-alt';
        }
    }
    });
    

    Here is what I have for the html side:

    <th>First Name<a ng-click="newOrderBy('_firstName')"><table-headers></table-headers></a></th>
    <th>Last Name<a ng-click="newOrderBy('_lastName')"><table-headers></table-headers></a></th>
    <tr ng-repeat="item in items | orderBy:orderBy:reverse>
    <td>{{item._firstName}}</td>
    <td>{{item._lastName}}</td>
    </tr>
    

    The order by is currently handled in the controller:

       $scope.newOrderBy = function(order) {
            $scope.orderBy = order;
            $scope.reverse = !$scope.reverse;
        };
    
  • mg1075
    mg1075 over 9 years
    This is a helpful, clever approach, yet it does not offer full encapsulation: if you have multiple tables on a page, there is a risk you will end up sorting two tables at once if you keep the same values in the by and/or reverse attributes.