Skip to content

Instantly share code, notes, and snippets.

@spitimage
Created May 1, 2014 22:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spitimage/df87a07d85f416ec47d0 to your computer and use it in GitHub Desktop.
Save spitimage/df87a07d85f416ec47d0 to your computer and use it in GitHub Desktop.
Lightweight AngularJS sortable grid
'use strict';
angular.module('moduleName')
.controller('GridCtrl', function ($scope) {
// Data for the sorted table demo
$scope.data = [
{field1: 'a', field2: 'z'},
{field1: 'b', field2: 'y'},
{field1: 'c', field2: 'x'},
{field1: 'd', field2: 'w'}
];
$scope.sortCb = function(field, dir){
$scope.$apply(function(){
$scope.data.sort(function(a, b){
if(a[field] < b[field]){
return -dir
}
if(a[field] > b[field]){
return dir
}
return 0;
})
})
}
});
'use strict';
angular.module('moduleName')
.directive('sortedtable', function () {
return {
restrict: 'E',
scope: {
sort: '='
},
controller: function ($scope) {
var children = [];
// Add child column subscribers
this.addChild = function(cb){
children.push(cb);
};
this.sort = function(field, dir){
// Invoke the sort callback if it exists
if($scope.sort){
$scope.sort(field, dir);
}
// Notify all children columns that a sort has been applied to this field
children.forEach(function(cb){
cb(field);
})
}
}
};
})
.directive('sortedcolumn', function () {
return {
restrict: 'A',
require: '^sortedtable',
scope: {},
link: function postLink(scope, element, attrs, controller) {
var origText = element.text();
var origField = attrs.sortedcolumn;
var direction = 1;
// On clicks, render the carat in the column and call the controller
element.on('click', function(){
if(direction > 0){
element.text(origText + ' \u25B2');
} else {
element.text(origText + ' \u25BC');
}
direction = -direction;
controller.sort(origField, direction);
});
// Register this column controller with the parent table controller
controller.addChild(function(field){
// Render original text if this column isn't the target
if(field != origField){
element.text(origText);
}
});
}
};
})
'use strict';
describe('Directive: sortedtable', function () {
beforeEach(module('moduleName'));
var scope, element;
var table = '<sortedtable sort="sortCb"><table><thead><tr>' +
'<th sortedcolumn="field1">Field1</th><th sortedcolumn="field2">Field2</th>' +
'</tr></thead></table></sortedtable>';
beforeEach(inject(function ($rootScope, $compile) {
scope = $rootScope.$new();
scope.sortCb = jasmine.createSpy('sort');
element = angular.element(table);
$compile(element)(scope);
}));
it('Sort callback should be called with first field', function () {
var th = angular.element(element.find('th')[0]);
th.triggerHandler('click');
expect(scope.sortCb).toHaveBeenCalledWith('field1', -1);
});
it('Sort callback should be called with second field', function () {
var th = angular.element(element.find('th')[1]);
th.triggerHandler('click');
expect(scope.sortCb).toHaveBeenCalledWith('field2', -1);
});
it('Change sort direction after second click', function () {
var th = angular.element(element.find('th')[0]);
th.triggerHandler('click');
th.triggerHandler('click');
expect(scope.sortCb).toHaveBeenCalledWith('field1', 1);
});
it('Display unicode up carat in header text after click', function () {
var th = angular.element(element.find('th')[0]);
th.triggerHandler('click');
expect(th.text()).toBe('Field1 \u25B2');
});
it('Display unicode down carat in header text after second click', function () {
var th = angular.element(element.find('th')[0]);
th.triggerHandler('click');
th.triggerHandler('click');
expect(th.text()).toBe('Field1 \u25BC');
});
});
<div ng-controller="GridCtrl">
<h3>Sorted Table Demo:</h3>
<sortedtable sort="sortCb">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th width="50%" sortedcolumn="field1">Field1</th>
<th width="50%" sortedcolumn="field2">Field2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in data">
<td>{{ item.field1 }}</td>
<td>{{ item.field2 }}</td>
</tr>
</tbody>
</table>
</sortedtable>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment