Created
February 24, 2014 19:07
-
-
Save nwpappas/9194765 to your computer and use it in GitHub Desktop.
An AngularJS directive implementation of Twitter Bootstrap's ScrollSpy, ported and updated from https://gist.github.com/alxhill/6886760.
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
app.directive('scrollSpy', function ($window) { | |
return { | |
restrict: 'A', | |
controller: function ($scope) { | |
$scope.spies = []; | |
this.addSpy = function (spyObj) { | |
$scope.spies.push(spyObj); | |
}; | |
}, | |
link: function (scope, elem, attrs) { | |
var spyElems; | |
spyElems = []; | |
scope.$watch('spies', function (spies) { | |
var spy, _i, _len, _results; | |
_results = []; | |
for (_i = 0, _len = spies.length; _i < _len; _i++) { | |
spy = spies[_i]; | |
if (spyElems[spy.id] == null) { | |
_results.push(spyElems[spy.id] = elem.find('#' + spy.id)); | |
} | |
} | |
return _results; | |
}); | |
$($window).scroll(function () { | |
var highlightSpy, pos, spy, _i, _len, _ref; | |
highlightSpy = null; | |
_ref = scope.spies; | |
// cycle through `spy` elements to find which to highlight | |
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
spy = _ref[_i]; | |
spy.out(); | |
// catch case where a `spy` does not have an associated `id` anchor | |
if (spyElems[spy.id].offset() === undefined) { | |
continue; | |
} | |
if ((pos = spyElems[spy.id].offset().top) - $window.scrollY <= 0) { | |
// the window has been scrolled past the top of a spy element | |
spy.pos = pos; | |
if (highlightSpy == null) { | |
highlightSpy = spy; | |
} | |
if (highlightSpy.pos < spy.pos) { | |
highlightSpy = spy; | |
} | |
} | |
} | |
// select the last `spy` if the scrollbar is at the bottom of the page | |
if ($(window).scrollTop() + $(window).height() >= $(document).height()) { | |
spy.pos = pos; | |
highlightSpy = spy; | |
} | |
return highlightSpy != null ? highlightSpy["in"]() : void 0; | |
}); | |
} | |
}; | |
}); | |
app.directive('spy', function ($location, $anchorScroll) { | |
return { | |
restrict: "A", | |
require: "^scrollSpy", | |
link: function(scope, elem, attrs, affix) { | |
elem.click(function () { | |
$location.hash(attrs.spy); | |
$anchorScroll(); | |
}); | |
affix.addSpy({ | |
id: attrs.spy, | |
in: function() { | |
elem.addClass('active'); | |
}, | |
out: function() { | |
elem.removeClass('active'); | |
} | |
}); | |
} | |
}; | |
}); |
For this to work with dynamically generated content, i.e., ng-repeat creating the DOM for both the navigation links and the header tags with matching ids, you must add a $timeout or an $evalAsync around the code that actually calls elem.find('#' + spy.id) else those elements don't exist yet and will not work as expected.
@ikend do you fixe the problem? If yes, can you send the solution?
As far as I understand, the $scope.spies.push(spyObj) in the this.addSpy function doesn't triggers the $watch('spies'... (watcher that adds the jquery element on the spyElems list). I'm not a master on angularjs and I cannot guess why this watcher doesn't trigger on a watched variable changes...
Thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Big thanks mate!