var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $http) {
$http.get('people.json').then(function (response) {
$scope.people = response.data;
console.log($scope.people.length);
});
// Sorting
$scope.sortProperty = '';
$scope.sortDirection = false;
$scope.sortBy = function (column) {
if ($scope.sortProperty === column) {
$scope.sortDirection = !$scope.sortDirection;
} else {
$scope.sortProperty = column;
$scope.sortDirection = false;
}
};
});
app.directive('tableFixedHead', function ($window, $document, $compile, $animate) {
// Debounce scroll to minimize lag, taken from lodash
// https://github.com/lodash/lodash/blob/master/vendor/underscore/underscore.js#L693
function debounce(func, wait, immediate) {
var timeout, args, context, timestamp, result;
return function() {
context = this;
args = arguments;
timestamp = new Date();
var later = function() {
var last = (new Date()) - timestamp;
if (last < wait) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) result = func.apply(context, args);
}
};
var callNow = immediate && !timeout;
if (!timeout) {
timeout = setTimeout(later, wait);
}
if (callNow) result = func.apply(context, args);
return result;
};
}
// Get scroll top, same logic as jQuery
// https://github.com/jquery/jquery/blob/73fe17299a840a8a7f3ffffcac15e32a88bd3d66/speed/jquery-basis.js#L1990
function scrollTop(element) {
element = element || $document[0].documentElement;
var body = $document[0].body;
return (element && element.scrollTop || body && body.scrollTop || 0);
}
return function (scope, element, attrs) {
var win = angular.element($window);
var clone;
function scroll() {
var elementOffset = element[0].offsetTop;
var offset = scrollTop() - elementOffset;
if (offset > 0 && clone === undefined) {
create();
} else if (offset <= 0) {
remove();
}
}
function create() {
var origHead = element.find('thead');
var origColumns = origHead.find('tr').children();
clone = origHead
.clone()
.css('left', element[0].offsetLeft + 'px')
.addClass('fixed-head');
$compile(clone.contents())(scope);
// Set table columnsizes
var columns = clone.find('tr').children();
angular.forEach(origColumns, function (column, i) {
angular.element(columns[i]).css('width', column.offsetWidth + 'px');
});
// Add class to table
element.addClass('has-fixed-head');
$animate.enter(clone, null, origHead);
}
function remove() {
if (clone) {
$animate.leave(clone, function () {
element.removeClass('has-fixed-head');
clone = undefined;
});
}
}
win.on('scroll', debounce(scroll, 20));
}
})
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<!--[if lt IE 9]>
<script data-require="respond.js@1.1.0" data-semver="1.1.0" src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.1.0/respond.min.js"></script>
<![endif]-->
<link data-require="bootstrap-css@3.0.0" data-semver="3.0.0" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js@1.1.x" src="http://code.angularjs.org/1.2.0-rc.2/angular.js" data-semver="1.2.0-rc2"></script>
<script data-require="angular-animate@1.2.0-rc2" data-semver="1.2.0-rc2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular-animate.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div class="container">
<div class="jumbotron">
<div class="container">
<h1>Fixed table heading</h1>
<p>By watching the scroll we can clone the thead when the table head goes out of view.</p>
<p>The directive shares the same scope as it's nested withing the table</p>
<p>In the example we also support sorting, since the fixed header gets run through $compile</p>
</div>
</div>
<table class="table" table-fixed-head="">
<thead class="fixed-head-animation">
<tr>
<th ng-click="sortBy('name')">Name <i class="glyphicon glyphicon-sort"></i>
</th>
<th ng-click="sortBy('age')">Age <i class="glyphicon glyphicon-sort"></i>
</th>
<th ng-click="sortBy('gender')">Gender <i class="glyphicon glyphicon-sort"></i>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="person in people | orderBy:sortProperty:sortDirection">
<td>{{person.name}}</td>
<td>{{person.age}}</td>
<td>{{person.gender}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
*[ng-click] {
cursor: pointer;
}
/* Gets added when the table heading is fixed */
.has-fixed-head {}
.fixed-head {
position: fixed;
left: 0;
top: 0;
z-index: 10000;
background: #fff;
}
/*
I Haven't got the animations to work yet :(
*/
.fixed-head-animation.ng-enter, .fixed-head-animation.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
}
.fixed-head-animation.ng-enter,
.fixed-head-animation.ng-leave.ng-leave-active {
opacity:0;
}
.fixed-head-animation.ng-enter.ng-enter-active,
.fixed-head-animation.ng-leave {
opacity:1;
}
[
{
"name": "Fields Horne",
"age": 32,
"gender": "male"
},
{
"name": "Gamble Mcleod",
"age": 29,
"gender": "male"
},
{
"name": "Watson Cunningham",
"age": 30,
"gender": "male"
},
{
"name": "Bernard Wright",
"age": 23,
"gender": "male"
},
{
"name": "Keller Conrad",
"age": 27,
"gender": "male"
},
{
"name": "Conner Valenzuela",
"age": 21,
"gender": "male"
},
{
"name": "Traci Barry",
"age": 37,
"gender": "female"
},
{
"name": "Victoria Mason",
"age": 28,
"gender": "female"
},
{
"name": "Luella Black",
"age": 21,
"gender": "female"
},
{
"name": "Lee Irwin",
"age": 27,
"gender": "male"
},
{
"name": "Ebony Jimenez",
"age": 26,
"gender": "female"
},
{
"name": "Short Norman",
"age": 26,
"gender": "male"
},
{
"name": "Deanne Patterson",
"age": 34,
"gender": "female"
},
{
"name": "Gabrielle Grimes",
"age": 39,
"gender": "female"
},
{
"name": "Holcomb Graves",
"age": 35,
"gender": "male"
},
{
"name": "Fitzgerald Joseph",
"age": 22,
"gender": "male"
},
{
"name": "Oconnor Jarvis",
"age": 32,
"gender": "male"
},
{
"name": "Tasha Ferrell",
"age": 22,
"gender": "female"
},
{
"name": "Scott Gregory",
"age": 27,
"gender": "male"
},
{
"name": "Rivas Combs",
"age": 25,
"gender": "male"
},
{
"name": "Trujillo Bright",
"age": 23,
"gender": "male"
},
{
"name": "Alicia Campos",
"age": 28,
"gender": "female"
},
{
"name": "Cruz Mann",
"age": 34,
"gender": "male"
},
{
"name": "French Bean",
"age": 26,
"gender": "male"
},
{
"name": "Tiffany Cherry",
"age": 29,
"gender": "female"
},
{
"name": "Georgia Alston",
"age": 22,
"gender": "female"
},
{
"name": "Jerry Moon",
"age": 30,
"gender": "female"
},
{
"name": "Ortega Kemp",
"age": 26,
"gender": "male"
},
{
"name": "Maricela Curry",
"age": 27,
"gender": "female"
},
{
"name": "Josefa Ford",
"age": 35,
"gender": "female"
},
{
"name": "Levine Haney",
"age": 31,
"gender": "male"
},
{
"name": "Hahn Jones",
"age": 36,
"gender": "male"
},
{
"name": "Garner Kent",
"age": 26,
"gender": "male"
},
{
"name": "Vasquez Mayer",
"age": 40,
"gender": "male"
},
{
"name": "Earline Hays",
"age": 22,
"gender": "female"
},
{
"name": "Olivia Shannon",
"age": 32,
"gender": "female"
},
{
"name": "Marisa Briggs",
"age": 20,
"gender": "female"
},
{
"name": "Allison Odonnell",
"age": 29,
"gender": "female"
},
{
"name": "Hickman Melton",
"age": 36,
"gender": "male"
},
{
"name": "Andrea Bauer",
"age": 33,
"gender": "female"
},
{
"name": "Sara Lindsay",
"age": 34,
"gender": "female"
},
{
"name": "Hensley Castaneda",
"age": 25,
"gender": "male"
},
{
"name": "Kristi Levine",
"age": 27,
"gender": "female"
},
{
"name": "Lina Yates",
"age": 33,
"gender": "female"
},
{
"name": "Mills Miller",
"age": 20,
"gender": "male"
},
{
"name": "Lilian Logan",
"age": 28,
"gender": "female"
},
{
"name": "Eve Woodard",
"age": 20,
"gender": "female"
},
{
"name": "Daugherty Little",
"age": 37,
"gender": "male"
},
{
"name": "Blankenship Sanford",
"age": 23,
"gender": "male"
},
{
"name": "Lucile Vinson",
"age": 26,
"gender": "female"
},
{
"name": "Morales Sandoval",
"age": 24,
"gender": "male"
},
{
"name": "Dunlap Elliott",
"age": 25,
"gender": "male"
},
{
"name": "Hamilton Boyd",
"age": 24,
"gender": "male"
},
{
"name": "Hutchinson Dunn",
"age": 20,
"gender": "male"
},
{
"name": "Richardson Snow",
"age": 36,
"gender": "male"
},
{
"name": "Foley Turner",
"age": 22,
"gender": "male"
},
{
"name": "Sue Whitney",
"age": 39,
"gender": "female"
},
{
"name": "Gina Calhoun",
"age": 37,
"gender": "female"
},
{
"name": "Christi Carter",
"age": 34,
"gender": "female"
},
{
"name": "Decker Hutchinson",
"age": 22,
"gender": "male"
},
{
"name": "Lesa Aguilar",
"age": 26,
"gender": "female"
},
{
"name": "Sherri Austin",
"age": 33,
"gender": "female"
},
{
"name": "Bianca Hunter",
"age": 24,
"gender": "female"
},
{
"name": "Hale Gilmore",
"age": 38,
"gender": "male"
},
{
"name": "Sharlene Holman",
"age": 21,
"gender": "female"
},
{
"name": "Love Massey",
"age": 28,
"gender": "male"
},
{
"name": "Harding Morrow",
"age": 40,
"gender": "male"
},
{
"name": "Audra Orr",
"age": 38,
"gender": "female"
},
{
"name": "Joy Spence",
"age": 32,
"gender": "female"
},
{
"name": "Whitney Garza",
"age": 27,
"gender": "female"
},
{
"name": "Alisha Stark",
"age": 32,
"gender": "female"
},
{
"name": "Cannon Atkins",
"age": 23,
"gender": "male"
},
{
"name": "Thornton Pierce",
"age": 35,
"gender": "male"
},
{
"name": "Santana Medina",
"age": 34,
"gender": "male"
},
{
"name": "Ava Hill",
"age": 32,
"gender": "female"
},
{
"name": "Alvarez Campbell",
"age": 33,
"gender": "male"
},
{
"name": "Webb Jenkins",
"age": 32,
"gender": "male"
},
{
"name": "Ware Lucas",
"age": 39,
"gender": "male"
},
{
"name": "Calhoun Mcdaniel",
"age": 28,
"gender": "male"
},
{
"name": "Bonnie Romero",
"age": 21,
"gender": "female"
},
{
"name": "York Gonzales",
"age": 39,
"gender": "male"
},
{
"name": "Wood Finley",
"age": 20,
"gender": "male"
},
{
"name": "Lucille Velez",
"age": 31,
"gender": "female"
},
{
"name": "Chang Knox",
"age": 29,
"gender": "male"
},
{
"name": "Mccoy Craft",
"age": 28,
"gender": "male"
},
{
"name": "Ina Perry",
"age": 38,
"gender": "female"
},
{
"name": "Effie Curtis",
"age": 23,
"gender": "female"
},
{
"name": "Henrietta Potter",
"age": 40,
"gender": "female"
},
{
"name": "Avis Pickett",
"age": 38,
"gender": "female"
},
{
"name": "Estrada Acosta",
"age": 32,
"gender": "male"
},
{
"name": "Sims Chan",
"age": 33,
"gender": "male"
},
{
"name": "Terrell Benjamin",
"age": 34,
"gender": "male"
},
{
"name": "Lamb Sparks",
"age": 23,
"gender": "male"
},
{
"name": "Paige Fitzgerald",
"age": 28,
"gender": "female"
},
{
"name": "Mai Chen",
"age": 36,
"gender": "female"
},
{
"name": "Emilia Hinton",
"age": 35,
"gender": "female"
},
{
"name": "Mccray Rush",
"age": 31,
"gender": "male"
},
{
"name": "Mercer Donovan",
"age": 33,
"gender": "male"
},
{
"name": "Clayton Mclean",
"age": 32,
"gender": "male"
},
{
"name": "Frankie Lewis",
"age": 36,
"gender": "female"
}
]