<!DOCTYPE html>
<html>

  <head>
    <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
    <script data-require="angular.js@*" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js"></script>
    <script src="service.js"></script>
    <script src="main.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>

  <body ng-app="myApp" ng-controller="myCtrl">
    <div >
      <div style="margin-left:5px;margin-top:10px" >
        <ang-table conf="config"></ang-table>
        
       
      </div>
      
    </div>
     <div style="margin-top: '1000px'">{{config | json}}</div>
  </body>

</html>
var myApp = angular.module('myApp');
myApp.controller('myCtrl', function($scope,candidates) {
  candidates.then(function(data){
    
  $scope.config.myData=data;
  });
  $scope.config = {
    heads: ['name', 'age', 'company', 'tech']
  };

});
myApp.directive('droppable', ['$parse',
  function($parse) {
    return {

      link: function(scope, element, attr) {
        function onDragOver(e) {
          if (e.preventDefault) {
            e.preventDefault();
          }
          if (e.stopPropagation) {
            e.stopPropagation();
          }
          e.dataTransfer.dropEffect = 'move';
          return false;
        }

        function onDrop(e) {
          console.log("dropped");
          if (e.preventDefault) {
            e.preventDefault();
          }
          if (e.stopPropagation) {
            e.stopPropagation();
          }
          var data = e.dataTransfer.getData("Text");
          data = angular.fromJson(data);
          var dropfn = attr.drop;
          var fn = $parse(attr.drop);
          var headerElem=e.target.closest('th');
          var textOfHeader=angular.element(headerElem).find("a");
          scope.$apply(function() {
            scope[dropfn](data, textOfHeader[0]);
          });

        }
        element.bind("dragover", onDragOver);
        element.bind("drop", onDrop);
      }
    };
  }
]);
myApp.directive('draggable', function() {
  return {
    link: function(scope, elem, attr) {
      elem.attr("draggable", true);
      var dragDataVal = '';
      var draggedGhostImgElemId = '';
      attr.$observe('dragdata', function(newVal) {
        dragDataVal = newVal;

      });
      attr.$observe('dragimage', function(newVal) {
        draggedGhostImgElemId = newVal;
      });
      elem.bind("dragstart", function(e) {
        var sendData = angular.toJson(dragDataVal);
        e.dataTransfer.setData("Text", sendData);
        if (attr.dragimage !== 'undefined') {
          e.dataTransfer.setDragImage(
            document.getElementById(draggedGhostImgElemId), 0, 0
          );
        }
        var dragFn = attr.drag;
        if (dragFn !== 'undefined') {
          scope.$apply(function() {
            scope[dragFn](sendData);
          })
        }
      });
    }
  };
});
myApp.directive('angTable', ['$compile',
  function($compile) {
    return {
      restrict: 'E',
      templateUrl: 'tabletemplate.html',
      replace: true,
      scope: {
        conf: "="
      },
      controller: function($scope) {
        $scope.predicate = 'age';
      $scope.reverse = true;
      $scope.numLimit=5;
      $scope.start = 0;
      $scope.$watch('conf.myData',function(newVal){
        if(newVal){
      $scope.pages=Math.ceil($scope.conf.myData.length/$scope.numLimit);
   
        }
      });
      $scope.hideNext=function(){
        if(($scope.start+ $scope.numLimit) < $scope.conf.myData.length){
          return false;
        }
        else 
        return true;
      };
       $scope.hidePrev=function(){
        if($scope.start===0){
          return true;
        }
        else 
        return false;
      };
      $scope.nextPage=function(){
        console.log("next pages");
        $scope.start=$scope.start+ $scope.numLimit;
        console.log( $scope.start)
      };
      $scope.PrevPage=function(){
        console.log("next pages");
        $scope.start=$scope.start - $scope.numLimit;
        console.log( $scope.start)
      };
      
         $scope.order = function(predicate) {
        $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
        $scope.predicate = predicate;
      };
        $scope.dragHead = '';
        $scope.dragImageId = "dragtable";
        $scope.handleDrop = function(draggedData,
          targetElem) {

          var swapArrayElements = function(array_object, index_a, index_b) {
            var temp = array_object[index_a];
            array_object[index_a] = array_object[index_b];
            array_object[index_b] = temp;
          };
          var srcInd = $scope.conf.heads.indexOf(draggedData);
          var destInd = $scope.conf.heads.indexOf(targetElem.textContent);
          swapArrayElements($scope.conf.heads, srcInd, destInd);
        };
        $scope.handleDrag = function(columnName) {
          $scope.dragHead = columnName.replace(/["']/g, "");
        };
      },
      compile: function(elem) {
        return function(ielem, $scope) {
          $compile(ielem)($scope);
        };
      }
    };
  }
]);
.hidtable {
    position: absolute;
    top: 0;
    left: 0;
    cursor:move;
    background:white;
    border-style:dotted;
    z-index:4;
}
.coverhidtable {
    position: absolute;
    top: 0;
    left: 0;
    cursor:move;
    background:white;
    color:white;
    z-index:4;
}
.acttable {
    position: absolute;
    top: 0;
    left: 0;
    cursor:move;
    z-index:5;
    background:white;
}
.acttable th{
  padding:10px;
 
}
.drag {
    background:orange;
    color:white;
    cursor:move;
}
.over {
    background: red;
    color:white;
}
 .sortorder:after {
    content: '\25b2';
  }
  .sortorder.reverse:after {
    content: '\25bc';
  }

This is a simple example of reordering of columns in a table using angular directives.
Basically this application uses 3 directives, myTable, draggable and droppable.
The diective angTable is an element directive, where it has an attribute named conf
The attribute 'conf'may contain an object consisting of head where we specify the table headers and one array of objects.
Directive named draggable has 3 attributes:
  drag:which specify a function defined which get fired when the dragging starts
  dragData:which specify the text to be transfered as the content of dragged element
  dragImage:the id of the element which ghost image should appear as the drag feedback
Directive named droppable has 1 attributes:
  drop:which specify a function defined which get fired when the drop occurs  
<div style="position:relative">
  <table class="hidtable" id="dragtable" border="1">
    <thead style="cursor:move">
      <th>{{dragHead}}</th>
    </thead>
    <tr ng-repeat="row in conf.myData">
      <td>{{row[dragHead]}}</td>
    </tr>
  </table>
  <table class="coverhidtable" border="1">
    <thead style="cursor:move">
      <th>{{dragHead}}</th>
    </thead>
    <tr ng-repeat="row in conf.myData">
      <td>{{row[dragHead]}}</td>
    </tr>
  </table>
  <table class="table table-bordered acttable" >
    <thead>
      <th style="cursor:move" draggable drag="handleDrag"  dragData="{{hd}}" dragImage="{{dragImageId}}" droppable drop="handleDrop" ng-repeat="hd in conf.heads">
        
        <a href="" ng-click="order(hd)">{{hd}}</a>
        <span class="sortorder" ng-show="predicate === hd" ng-class="{reverse:reverse}"></span>
    
      </th>
    </thead>
    <tbody>
      <tr ng-repeat="data in conf.myData | orderBy:predicate:reverse | limitTo:numLimit:start">
        <td ng-repeat="d in conf.heads"><span>{{data[d]}}</span>
        </td>
      </tr>
      <tr>
        <td colspan="5">Page(s): {{pages}} <span style="padding:5px"> showing {{numLimit}} records per page</span>
         <span style="float:right;padding:5px"><a ng-hide="hidePrev()" href="" ng-click="PrevPage()">Prev</a></span>
        <span style="float:right;padding:5px"><a ng-hide="hideNext()" href="" ng-click="nextPage()">Next</a></span></td>
      </tr>
    </tbody>
  </table>
  
  
</div>
 {
   "myData": [{
     
     "name": "Jay",
     "age": 27,
     "company": "ABC",
     "tech": "Js"
   }, {
     "name": "Rayn",
     "age": 30,
     "company": "NBC",
     "tech": ".net"
   }, {
     "name": "Stan",
     "age": 29,
     "company": "Amazon",
     "tech": "Java"
   }, {
     "name": "Stan",
     "age": 29,
     "company": "Amazon",
     "tech": "Java"
   },
    {
     "name": "Bob",
     "age": 40,
     "company": "E-bay",
     "tech": "C"
   },
   {
     "name": "Clark",
     "age": 32,
     "company": "Google",
     "tech": "Python"
   }]
 }
var mainModule = angular.module('myApp',[]);
mainModule.factory("candidates",function($http,$q){
  
 this.candidates=[];
 var self=this;
 var defer=$q.defer();
   $http.get("./data.json").success(function(data){
  var candidates=data.myData;
    defer.resolve(candidates);
    
  })
 return defer.promise;
});