Last active
August 26, 2016 14:53
-
-
Save bbrown/6bd7811ec95ee6993b98 to your computer and use it in GitHub Desktop.
Angular directive that makes a table's thead fixed at top of screen on scrolling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| angular.module("app").directive("fixedHeader", function($timeout, $window) | |
| { | |
| return { | |
| restrict: "A", | |
| scope: false, | |
| link: function(scope, element, attrs) | |
| { | |
| var waitTime = attrs.fixedHeader || 0; | |
| var collectionToWatch = attrs.fhCollection; | |
| var tableTop, topPos, tableLeft; | |
| var widths = []; | |
| function setup() | |
| { | |
| var IS_MOBILE = ("ontouchstart" in document.documentElement) || document.documentElement.clientWidth < 1024; | |
| tableTop = element[0].offsetTop; | |
| // Handles the mobile nav header's fixed position | |
| topPos = (!IS_MOBILE) ? 0 : 50; | |
| tableLeft = element[0].offsetLeft; | |
| // Save the current widths of the thead th's | |
| for (var i = 0, l = element[0].tHead.firstElementChild.cells.length; i < l; i++) | |
| { | |
| widths.push(element[0].tHead.firstElementChild.cells[i].offsetWidth); | |
| } | |
| } | |
| // Wait for data binding to complete before getting coordinates | |
| if (collectionToWatch) | |
| { | |
| var cw = scope.$watch(collectionToWatch, function(newValue, oldValue) | |
| { | |
| if (newValue && newValue.length > 0) | |
| { | |
| // Run the setup on next tick since we know that the collection is set | |
| // and the table rendered (though not shown yet) | |
| $timeout(setup, 0); | |
| cw(); | |
| } | |
| }); | |
| } | |
| else | |
| { | |
| // If no collection is associated, just use either the provided timeout period | |
| // or 0 for next tick | |
| $timeout(setup, waitTime); | |
| } | |
| // Use the thead's tr to clone since it has a height after changing to fixed | |
| var thead = element[0].tHead.firstElementChild; | |
| // The thead clone is created and removed on scrolling to keep the offsetHeight's constant | |
| var theadClone = angular.element(thead).clone().css({ position:"static", top:"0px" }); | |
| // This variable reduces the DOM manipulation to just once during the positioning change | |
| var madeTheadFixed = false; | |
| function handleScroll() | |
| { | |
| // Handle vertical scrolling | |
| if (!madeTheadFixed && $window.pageYOffset > tableTop) | |
| { | |
| madeTheadFixed = true; | |
| // Explicitly set the widths of the th's to prevent shrinkage | |
| widths.forEach(function(width, index) | |
| { | |
| thead.cells[index].style.width = width + "px"; | |
| // console.log("was", thead.cells[index].offsetWidth, "is", width); | |
| }); | |
| thead.style.position = "fixed"; | |
| thead.style.top = topPos + "px"; | |
| thead.style.backgroundColor = "#000"; | |
| thead.style.zIndex = "10"; | |
| theadClone.css("height", thead.offsetHeight + "px"); | |
| element.addClass("fh-scrolling"); | |
| angular.element(thead).parent().append(theadClone); | |
| } | |
| else if (madeTheadFixed && $window.pageYOffset < tableTop) | |
| { | |
| madeTheadFixed = false; | |
| thead.style.position = "static"; | |
| thead.style.top = "0px"; | |
| theadClone.remove(); | |
| element.removeClass("fh-scrolling"); | |
| } | |
| // Handle horizontal scrolling | |
| if ($window.pageXOffset > 0) | |
| { | |
| thead.style.left = (tableLeft - $window.pageXOffset) + "px"; | |
| } | |
| else | |
| { | |
| thead.style.left = tableLeft + "px"; | |
| } | |
| } | |
| angular.element($window).on("scroll", handleScroll); | |
| element.addClass("fh"); | |
| // Clean up after self | |
| scope.$on("$destroy", function() | |
| { | |
| angular.element($window).off("scroll", handleScroll); | |
| tableTop = undefined; | |
| tableLeft = undefined; | |
| thead = undefined; | |
| }); | |
| } | |
| } | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment