AngularJS Directive to generate a table of contents
-
21-12-2019 - |
Question
Imagine a html text that contains headlines (h1-h6). In my situtation it is also present as DOM in a html page. So using jQuery I would do something like $('.text').find('h1,h2,h3,h4,h5,h6')
to extract all the headlines.
But I don't want to use jQuery or any other heavy framework. How can I do this with angularJS? Please remember that I need the headlines in the correct order to display it as a table of contents.
Solution
So here is my final solution. The ng-model part is used to update the headlines when the text is updated.
.directive('tableOfContents', function(){
return {
restrict:'A',
require:'?ngModel',
link : function(scope, elm, attrs,ngModel) {
function updateHeadlines() {
scope.headlines=[];
angular.forEach(elm[0].querySelectorAll('h1,h2,h3,h4,h5,h6'), function(e){
scope.headlines.push({
level: e.tagName[1],
label: angular.element(e).text(),
element: e
});
});
}
// avoid memoryleaks from dom references
scope.$on('$destroy',function(){
scope.headlines=[];
});
// scroll to one of the headlines
scope.scrollTo=function(headline){
headline.element.scrollIntoView();
}
// when the html updates whe update the headlines
ngModel.$render = updateHeadlines;
updateHeadlines();
}
}
})
Usage:
<a ng-repeat="headline in headlines" ng-click="scrollTo(headline)">{{headline.label}}</a>
<div table-of-contents ng-model="html">{{html}}</div>
OTHER TIPS
You're in luck, and should be able to use angular.element almost exactly the same way as you would use jQuery.
angular.element('h1')
will find h1
elements.
You can find the elements having the class ".text" using
angular.element(document.querySelectorAll(".text"));