Skip to content

Instantly share code, notes, and snippets.

@datchley
Created March 9, 2015 20:01
Show Gist options
  • Save datchley/c3e5f7435d221a4d2fc4 to your computer and use it in GitHub Desktop.
Save datchley/c3e5f7435d221a4d2fc4 to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/qiyuqapelu
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://code.jquery.com/jquery.min.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
<style id="jsbin-css">
td.sorted,
th.sorted {
font-weight: 900;
}
td i.fa-sort,
th i.fa-sort {
color: #ccc;
}
table.bh-data-table tfoot {
font-size: small;
color: #999;
}
table.table-hover tbody tr:hover {
background-color: #E2E2E3;
}
</style>
</head>
<body ng-controller="myController">
<table bh-data-table data="data" meta="meta" sort-column="age" cell-action="linkAction" row-action="rowAction">
</table>
<script id="jsbin-javascript">
angular.module('app', [])
.controller('myController', ['$scope', function($scope) {
$scope.data = [
{ id: 1, name: 'Dave', age: 39, modified: Date.now() },
{ id: 2, name: 'Kurt', age: 43, modified: Date.now() },
{ id: 3, name: 'Mitch', age: 45, modified: Date.now() },
{ id: 4, name: 'Jay', age: 42, modified: Date.now() }
];
$scope.meta = [
{ description: 'Id', name: 'id', filter: null, link: true },
{ description: 'Name', name: 'name', filter: null, link: true },
{ description: 'Age', name: 'age', filter: null },
{ description: 'Modified', name: 'modified', filter: 'date:\'EEEE, yyyy-MM-dd\' | uppercase' }
];
$scope.linkAction = function(row, columnName) {
var scol = (typeof columnName !== 'undefined') ? '(column=' + columnName + ')' : '';
console.log("> row ", row);
alert(">EVENT(td click) linking to " + scol + " record id: " + row.id);
};
$scope.rowAction = function(row, columnName){
console.log("args: ", arguments);
alert(">EVENT(tr click) row: " + row.id + ", column: " + columnName);
};
}])
.directive('bhDataTable', ['$compile', '$parse', function($compile, $parse) {
function clearSelection() {
if (document.selection && document.selection.empty) {
document.selection.empty();
}
else if (window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
}
}
return {
restrict: 'AE',
replace: true,
template: '<table class="table table-striped table-hover bh-data-table">' +
'<thead><tr>' +
'<th ng-repeat="col in meta" ng-class="getSortClass(meta[$index].name)" col-id="{{meta[$index].name}}" >' +
'<i ng-class="getSortIcon(col.name)"></i> <a href="">{{col.description}}</a>' +
'</tr></th>' +
'</thead>' +
'<tbody>' +
'<tr ng-repeat="row in data | orderBy:sort.column:sort.direction" ng-init="rowIndex = $index" row-id="{{$index}}" data-row="{{row}}">' +
'<td ng-repeat="col in meta" col-name="{{col.name}}">' +
'<span ng-if="!col.link">{{evalField(col.name, row, col)}}</span>' +
'<span ng-if="col.link"><a href="">' +
'{{evalField(col.name, row, col)}}' +
'</a></span>' +
'</td>' +
'</tr>' +
'</tbody>' +
'<tfoot>' +
'<tr><td colspan="{{meta.length}}"></td></tr>' +
'</tfoot>' +
'</table>',
scope: {
data: '=',
meta: '=',
sortColumn: '@',
sortDirection: '@',
cellAction: '&',
rowAction: '&'
},
controller: function($scope) {
$scope.getSortIcon = function(name) {
return (name === $scope.sort.column) ?
['fa', ($scope.sort.direction ? 'fa-sort-up' : 'fa-sort-down')] :
['fa', 'fa-sort'];
};
$scope.getSortClass = function(name) {
return (name == $scope.sortColumn) ? 'sorted' : '';
};
$scope.evalField = function(colname, row, meta) {
if (meta.filter)
return $parse(colname + '|' + meta.filter)(row);
else
return $parse(colname)(row);
};
},
link: function($scope, elm, attrs, ctrlr, transclude) {
$scope.sort = {
column: 'id',
direction: false
};
if (attrs.sortColumn) {
$scope.sort.column = attrs.sortColumn;
}
if (attrs.sortDirection) {
var sdir = attrs.sortDirection.trim().toLowerCase();
sdir = /(asc|desc)/.test(sdir) ? sdir : false;
$scope.sort.direction = attrs.sortDirection == 'asc' ? true : false;
}
$scope.setfooterText = function(elm) {
var tmpl = $compile('<span><strong>{{meta.length}}</strong> records</span>');
angular.element(elm.find('tfoot tr td')).append(tmpl($scope));
};
$scope.setfooterText(elm);
elm.on('click', 'thead th a', function(ev) {
var $target = $(ev.currentTarget),
$th = $target.parent('th'),
col = $th.attr('col-id');
// remove prevoius 'sorted' class
elm.find('th').removeClass('sorted');
// add 'sorted' to this header
$th.addClass('sorted');
$scope.$apply(function() {
$scope.sort.column = col;
$scope.sort.direction = !$scope.sort.direction;
});
});
elm.on('click', 'tbody td a', function(ev) {
var $td = $(ev.currentTarget).parents('td'),
$tr = $td.parents('tr'),
row = $tr.data('row'),
colname = $td.attr('col-name');
if ($scope.cellAction && (typeof $scope.cellAction === 'function')) {
$scope.cellAction()(row, colname);
}
console.log("click handler method");
});
elm.on('dblclick', 'tbody td', function(ev) {
var $td = $(ev.currentTarget),
$tr = $td.parents('tr'),
row = $tr.data('row'),
colname = $td.attr('col-name');
clearSelection();
console.log("double click on row=%o, column=%s",row, colname);
if ($scope.rowAction && (typeof $scope.rowAction === 'function')) {
console.log("$scope: ", $scope);
$scope.rowAction()(row, colname);
}
});
}
};
}]);
</script>
<script id="jsbin-source-html" type="text/html"><!DOCTYPE html>
<html ng-app="app">
<head>
<script src="//code.jquery.com/jquery.min.js"><\/script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"><\/script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"><\/script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller="myController">
<table bh-data-table data="data" meta="meta" sort-column="age" cell-action="linkAction" row-action="rowAction">
</table>
</body>
</html></script>
<script id="jsbin-source-css" type="text/css">td.sorted,
th.sorted {
font-weight: 900;
}
td i.fa-sort,
th i.fa-sort {
color: #ccc;
}
table.bh-data-table tfoot {
font-size: small;
color: #999;
}
table.table-hover tbody tr:hover {
background-color: #E2E2E3;
}</script>
<script id="jsbin-source-javascript" type="text/javascript">angular.module('app', [])
.controller('myController', ['$scope', function($scope) {
$scope.data = [
{ id: 1, name: 'Dave', age: 39, modified: Date.now() },
{ id: 2, name: 'Kurt', age: 43, modified: Date.now() },
{ id: 3, name: 'Mitch', age: 45, modified: Date.now() },
{ id: 4, name: 'Jay', age: 42, modified: Date.now() }
];
$scope.meta = [
{ description: 'Id', name: 'id', filter: null, link: true },
{ description: 'Name', name: 'name', filter: null, link: true },
{ description: 'Age', name: 'age', filter: null },
{ description: 'Modified', name: 'modified', filter: 'date:\'EEEE, yyyy-MM-dd\' | uppercase' }
];
$scope.linkAction = function(row, columnName) {
var scol = (typeof columnName !== 'undefined') ? '(column=' + columnName + ')' : '';
console.log("> row ", row);
alert(">EVENT(td click) linking to " + scol + " record id: " + row.id);
};
$scope.rowAction = function(row, columnName){
console.log("args: ", arguments);
alert(">EVENT(tr click) row: " + row.id + ", column: " + columnName);
};
}])
.directive('bhDataTable', ['$compile', '$parse', function($compile, $parse) {
function clearSelection() {
if (document.selection && document.selection.empty) {
document.selection.empty();
}
else if (window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
}
}
return {
restrict: 'AE',
replace: true,
template: '<table class="table table-striped table-hover bh-data-table">' +
'<thead><tr>' +
'<th ng-repeat="col in meta" ng-class="getSortClass(meta[$index].name)" col-id="{{meta[$index].name}}" >' +
'<i ng-class="getSortIcon(col.name)"></i> <a href="">{{col.description}}</a>' +
'</tr></th>' +
'</thead>' +
'<tbody>' +
'<tr ng-repeat="row in data | orderBy:sort.column:sort.direction" ng-init="rowIndex = $index" row-id="{{$index}}" data-row="{{row}}">' +
'<td ng-repeat="col in meta" col-name="{{col.name}}">' +
'<span ng-if="!col.link">{{evalField(col.name, row, col)}}</span>' +
'<span ng-if="col.link"><a href="">' +
'{{evalField(col.name, row, col)}}' +
'</a></span>' +
'</td>' +
'</tr>' +
'</tbody>' +
'<tfoot>' +
'<tr><td colspan="{{meta.length}}"></td></tr>' +
'</tfoot>' +
'</table>',
scope: {
data: '=',
meta: '=',
sortColumn: '@',
sortDirection: '@',
cellAction: '&',
rowAction: '&'
},
controller: function($scope) {
$scope.getSortIcon = function(name) {
return (name === $scope.sort.column) ?
['fa', ($scope.sort.direction ? 'fa-sort-up' : 'fa-sort-down')] :
['fa', 'fa-sort'];
};
$scope.getSortClass = function(name) {
return (name == $scope.sortColumn) ? 'sorted' : '';
};
$scope.evalField = function(colname, row, meta) {
if (meta.filter)
return $parse(colname + '|' + meta.filter)(row);
else
return $parse(colname)(row);
};
},
link: function($scope, elm, attrs, ctrlr, transclude) {
$scope.sort = {
column: 'id',
direction: false
};
if (attrs.sortColumn) {
$scope.sort.column = attrs.sortColumn;
}
if (attrs.sortDirection) {
var sdir = attrs.sortDirection.trim().toLowerCase();
sdir = /(asc|desc)/.test(sdir) ? sdir : false;
$scope.sort.direction = attrs.sortDirection == 'asc' ? true : false;
}
$scope.setfooterText = function(elm) {
var tmpl = $compile('<span><strong>{{meta.length}}</strong> records</span>');
angular.element(elm.find('tfoot tr td')).append(tmpl($scope));
};
$scope.setfooterText(elm);
elm.on('click', 'thead th a', function(ev) {
var $target = $(ev.currentTarget),
$th = $target.parent('th'),
col = $th.attr('col-id');
// remove prevoius 'sorted' class
elm.find('th').removeClass('sorted');
// add 'sorted' to this header
$th.addClass('sorted');
$scope.$apply(function() {
$scope.sort.column = col;
$scope.sort.direction = !$scope.sort.direction;
});
});
elm.on('click', 'tbody td a', function(ev) {
var $td = $(ev.currentTarget).parents('td'),
$tr = $td.parents('tr'),
row = $tr.data('row'),
colname = $td.attr('col-name');
if ($scope.cellAction && (typeof $scope.cellAction === 'function')) {
$scope.cellAction()(row, colname);
}
console.log("click handler method");
});
elm.on('dblclick', 'tbody td', function(ev) {
var $td = $(ev.currentTarget),
$tr = $td.parents('tr'),
row = $tr.data('row'),
colname = $td.attr('col-name');
clearSelection();
console.log("double click on row=%o, column=%s",row, colname);
if ($scope.rowAction && (typeof $scope.rowAction === 'function')) {
console.log("$scope: ", $scope);
$scope.rowAction()(row, colname);
}
});
}
};
}]);
</script></body>
</html>
td.sorted,
th.sorted {
font-weight: 900;
}
td i.fa-sort,
th i.fa-sort {
color: #ccc;
}
table.bh-data-table tfoot {
font-size: small;
color: #999;
}
table.table-hover tbody tr:hover {
background-color: #E2E2E3;
}
angular.module('app', [])
.controller('myController', ['$scope', function($scope) {
$scope.data = [
{ id: 1, name: 'Dave', age: 39, modified: Date.now() },
{ id: 2, name: 'Kurt', age: 43, modified: Date.now() },
{ id: 3, name: 'Mitch', age: 45, modified: Date.now() },
{ id: 4, name: 'Jay', age: 42, modified: Date.now() }
];
$scope.meta = [
{ description: 'Id', name: 'id', filter: null, link: true },
{ description: 'Name', name: 'name', filter: null, link: true },
{ description: 'Age', name: 'age', filter: null },
{ description: 'Modified', name: 'modified', filter: 'date:\'EEEE, yyyy-MM-dd\' | uppercase' }
];
$scope.linkAction = function(row, columnName) {
var scol = (typeof columnName !== 'undefined') ? '(column=' + columnName + ')' : '';
console.log("> row ", row);
alert(">EVENT(td click) linking to " + scol + " record id: " + row.id);
};
$scope.rowAction = function(row, columnName){
console.log("args: ", arguments);
alert(">EVENT(tr click) row: " + row.id + ", column: " + columnName);
};
}])
.directive('bhDataTable', ['$compile', '$parse', function($compile, $parse) {
function clearSelection() {
if (document.selection && document.selection.empty) {
document.selection.empty();
}
else if (window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
}
}
return {
restrict: 'AE',
replace: true,
template: '<table class="table table-striped table-hover bh-data-table">' +
'<thead><tr>' +
'<th ng-repeat="col in meta" ng-class="getSortClass(meta[$index].name)" col-id="{{meta[$index].name}}" >' +
'<i ng-class="getSortIcon(col.name)"></i> <a href="">{{col.description}}</a>' +
'</tr></th>' +
'</thead>' +
'<tbody>' +
'<tr ng-repeat="row in data | orderBy:sort.column:sort.direction" ng-init="rowIndex = $index" row-id="{{$index}}" data-row="{{row}}">' +
'<td ng-repeat="col in meta" col-name="{{col.name}}">' +
'<span ng-if="!col.link">{{evalField(col.name, row, col)}}</span>' +
'<span ng-if="col.link"><a href="">' +
'{{evalField(col.name, row, col)}}' +
'</a></span>' +
'</td>' +
'</tr>' +
'</tbody>' +
'<tfoot>' +
'<tr><td colspan="{{meta.length}}"></td></tr>' +
'</tfoot>' +
'</table>',
scope: {
data: '=',
meta: '=',
sortColumn: '@',
sortDirection: '@',
cellAction: '&',
rowAction: '&'
},
controller: function($scope) {
$scope.getSortIcon = function(name) {
return (name === $scope.sort.column) ?
['fa', ($scope.sort.direction ? 'fa-sort-up' : 'fa-sort-down')] :
['fa', 'fa-sort'];
};
$scope.getSortClass = function(name) {
return (name == $scope.sortColumn) ? 'sorted' : '';
};
$scope.evalField = function(colname, row, meta) {
if (meta.filter)
return $parse(colname + '|' + meta.filter)(row);
else
return $parse(colname)(row);
};
},
link: function($scope, elm, attrs, ctrlr, transclude) {
$scope.sort = {
column: 'id',
direction: false
};
if (attrs.sortColumn) {
$scope.sort.column = attrs.sortColumn;
}
if (attrs.sortDirection) {
var sdir = attrs.sortDirection.trim().toLowerCase();
sdir = /(asc|desc)/.test(sdir) ? sdir : false;
$scope.sort.direction = attrs.sortDirection == 'asc' ? true : false;
}
$scope.setfooterText = function(elm) {
var tmpl = $compile('<span><strong>{{meta.length}}</strong> records</span>');
angular.element(elm.find('tfoot tr td')).append(tmpl($scope));
};
$scope.setfooterText(elm);
elm.on('click', 'thead th a', function(ev) {
var $target = $(ev.currentTarget),
$th = $target.parent('th'),
col = $th.attr('col-id');
// remove prevoius 'sorted' class
elm.find('th').removeClass('sorted');
// add 'sorted' to this header
$th.addClass('sorted');
$scope.$apply(function() {
$scope.sort.column = col;
$scope.sort.direction = !$scope.sort.direction;
});
});
elm.on('click', 'tbody td a', function(ev) {
var $td = $(ev.currentTarget).parents('td'),
$tr = $td.parents('tr'),
row = $tr.data('row'),
colname = $td.attr('col-name');
if ($scope.cellAction && (typeof $scope.cellAction === 'function')) {
$scope.cellAction()(row, colname);
}
console.log("click handler method");
});
elm.on('dblclick', 'tbody td', function(ev) {
var $td = $(ev.currentTarget),
$tr = $td.parents('tr'),
row = $tr.data('row'),
colname = $td.attr('col-name');
clearSelection();
console.log("double click on row=%o, column=%s",row, colname);
if ($scope.rowAction && (typeof $scope.rowAction === 'function')) {
console.log("$scope: ", $scope);
$scope.rowAction()(row, colname);
}
});
}
};
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment