var app = angular.module('plunker', []);
app.controller('MainCtrl', ["$scope","sortableColumnsService",function($scope,sortableColumnsService) {
$scope.list = [
{name:"dani din",age:57,role:"admin"},
{name:"moshe levi",age:21,role:"user"},
{name:"ziv cohen",age:28, role:"user"},
{name:"dafna shkuri",age:45, role:"user"},
{name:"rani ko", age:24,role:"admin"}
];
//The directive mediator which we send to the directive (via markup)
$scope.sharedLogic = {};
}]);
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<!--Bootstrap 3.1.1 CSS from CDN-->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<!--Font-Awsome CSS from CDN-->
<link href="//netdna.bootstrapcdn.com/font-awesome/3.1.1/css/font-awesome.css" rel="stylesheet">
<!--My CSS file-->
<link rel="stylesheet" href="style.css" />
</head>
<body ng-controller="MainCtrl">
<!--This is the "heading" row which enable sortign as a directive-->
<sortable-columns-headers-row shared-logic="sharedLogic" items-to-sort="list"></sortable-columns-headers-row>
<!--The rows of the table being repeted using ngRepeat-->
<div ng-repeat="item in list">
<div class="row tableRow" ng-class="{'isOpen':item.open}" ng-click="item.open = !item.open">
<div class='col-xs-3'>{{item.name}}</div>
<div class='col-xs-2'>{{item.age}}</div>
<div class='col-xs-2'>{{item.role}}</div>
</div>
<!--The collapsable container of each row -->
<div class="row" ng-class="{'collapse':!item.open}">
<div class="col-xs-12 rowCntent">
This is additional collapsable data: <br />
<strong>Name: </strong> {{item.name}} <br />
<strong>Age: </strong> {{item.age}} <br />
<strong>Role: </strong> {{item.role}} <br />
</div>
</div>
</div>
<!--Scripts-->
<!--AngularJS-->
<script data-require="angular.js@1.2.x" src="https://code.angularjs.org/1.2.16/angular.js" data-semver="1.2.16"></script>
<!--Underscore-->
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<!--My App -->
<script src="app.js"></script>
<!--Sortable colunbs header directive -->
<script src="sortable-columns-headers.directive.js"></script>
<!--Sortable colunbs header service -->
<script src="sortable-columns-headers.service.js"></script>
</body>
</html>
/* Put your css in here */
.tableRow:hover{
cursor:pointer;
background-color:gray;
}
.tableRow.isOpen{
background-color:gray;
}
.rowCntent{
background-color:yellow;
padding:10px;
margin-left:10px;
}
.columnDisabled{
color:gray;
}
<div class="row">
<div ng-repeat="column in sortableColumnsService.columns" class="{{column.class}}" ng-class="{'columnDisabled':!sortableColumnsService.enableSorting}">
<div ng-if="column.sortable" ng-click="columnClicked(column)" style="cursor:pointer;">
<strong>{{column.text}} <i ng-if="column.sortable"
ng-class="
{
'icon-sort':column.predicate !== sortableColumnsService.thisColumnToSort.predicate,
'icon-sort-down':column.predicate == sortableColumnsService.thisColumnToSort.predicate && !column.reverse,
'icon-sort-up': column.predicate == sortableColumnsService.thisColumnToSort.predicate && column.reverse
}"></i></strong>
</div>
<div ng-if="column.sortable == false"> <!-- Show only text with no sorting icons -->
<strong>{{column.text}}</strong>
</div>
</div>
</div>
/**
*The directive which holds the sorting logic of the itemsToSort array (uses underscore "sortBy")
**/
app.directive('sortableColumnsHeadersRow', ["sortableColumnsService",function (sortableColumnsService) {
return {
restrict:'E',
replace:true,
templateUrl:"sortable-columns-headers.tpl.html",
scope:{
itemsToSort:"=",
sharedLogic:"="
},
link:function(scope,elm,attr){
scope.sortableColumnsService = sortableColumnsService;
scope.columnClicked = function(column){
if(scope.sortableColumnsService.enableSorting){
if(scope.sortableColumnsService.thisColumnToSort.predicate === column.predicate){
scope.sortableColumnsService.thisColumnToSort.reverse = !scope.sortableColumnsService.thisColumnToSort.reverse;
}else{
scope.sortableColumnsService.thisColumnToSort = column;
}
scope.sortBy(scope.sortableColumnsService.thisColumnToSort);
}
};
/**
* This function sorts the items according to the column selected
**/
scope.sortBy = function(column){
scope.itemsToSort = _.sortBy(scope.itemsToSort,function(obj){
switch (column.dataType){
case "number":
return Number(obj[column.predicate]);
case "date":
return new Date(obj[column.predicate]);
default:
return obj[column.predicate].toString();
}
});
if(column.reverse){
scope.itemsToSort = scope.itemsToSort.reverse();
}
};
/**
* This function available to the controller via the sharedLogic object
* and it manually sorts the items acording the selected column
**/
scope.sharedLogic.sort = function(){
scope.sortBy(scope.sortableColumnsService.thisColumnToSort);
};
/**
* This function available to the controller via the sharedLogic object
* Tt enabling or disabeling the sorting
**/
scope.sharedLogic.isEnableSorting = function(val){
scope.sortableColumnsService.enableSorting = val;
};
//Initiation of the directive
scope.sortableColumnsService.thisColumnToSort = scope.sortableColumnsService.columns[0];
scope.sortBy(scope.sortableColumnsService.thisColumnToSort);
}
}
}]);
/**
*The service which holds properties regarding the columns headers
* It should be changed according to the items which are being passed to the directive
**/
app.service("sortableColumnsService",[function(){
return {
enableSorting:true, // Set it to false for disabel sorting
columns:[
{
text:"Name",
class:"col-xs-3",
predicate:"name",
sortable:true,
reverse:true
},
{
text:"Age",
class:"col-xs-2",
sortable:true,
predicate:"age",
reverse:false,
dataType:"number"
},
{
text:"Role",
class:"col-xs-2",
sortable:true,
predicate:"role",
reverse:false
}
]
}
}])