AngularJS blog archive directive

Sul Aga photo
0
Last Updated
Jan 22, 2016
Source Code

Introduction

This blog will explain the blog archive AngularJS directive and how to use it. This directive will group your blogs by year and month and display them in a collapsible tree. The directive comes with its own style which you can customize to match your site theme.

The blog archive directive

The main functionality of this directive is to group a list of blogs by their created date. The grouping happen on 2 levels, namely year and month. Here is a full listing of the directive code.

function blogArchive() {
    return {
        templateUrl: '/templates/blogArchive.tpl.html',
        scope: {
            blogs: '=blogs'
        },
        replace: true,
        controller: //see below for details,
        link: function ($scope, element, attrs) {
            $scope.setupBlogs();
        }
    }
}

I am using a template for my blog archive. The link function is calling setupBlogs method to setup the blogs collection that this directive is expecting. Here is the full listings for the controller

controller: ['$scope', '_', function ($scope, _) {

    $scope.setupBlogs = function () {
        var totalBlogsTemp = 0;
        $scope.archive = [];
        var years = _.groupBy($scope.blogs,
            function (blog) {
                return new Date(blog.dateCreated).getFullYear();
            });
        for (var year in years) {
            $scope.archive.push(
                {
                    yearName: year,
                    yearTotalBlogs: years[year].length,
                    months: getMonthGroup(years[year])
                });
            totalBlogsTemp += years[year].length;
        }
        $scope.archive.reverse();
        $scope.totalBlogs = totalBlogsTemp;
    };

    var getMonthGroup = function (yearGroupBlogs) {
        var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
        var monthsGroup = [];

        var months = _.groupBy(yearGroupBlogs,
            function (blog) {
                return monthNames[new Date(blog.dateCreated).getMonth()];
            });

        for (var month in months) {
            monthsGroup.push({ monthName: month, monthBlogs: months[month] });
        }

        return monthsGroup;
    };
    $scope.toggleDisplay = function (elementId) {
        var element = document.getElementById(elementId);
        var display = element.style.display;
        element.style.display = display == "block" ? "none" : "block";
    };
}
]

This controller accepts $scope as a dependency. It also accepts underscore as a dependency. This controller comprises of 3 methods and they are:

  • setupBlogs will group the blogs array by year
  • getMonthGroup will receive a blog array that is already grouped by year and group the blogs in it by month
  • toggleDisplay will hide/display a year or month tree node

The html template

This directive is using an html template that is based on bootstrap framework. Here is a full listing of the html template behind this directive.

<div class="panel panel-primary blog-archive-panel">
    <div class="panel-heading blog-archive-panel-heading">
        <h3 class="panel-title blog-archive-panel-title">
            Archive <span class="badge">{{totalBlogs}}</span>
        </h3>
    </div>
    <div class="panel-body blog-archive-panel-body">
        <ul>
            <li ng-repeat="yearGroup in archive">
                <div class="yearGroup" ng-click="toggleDisplay('arch_' + yearGroup.yearName)">
                    {{yearGroup.yearName}} <span class="badge">{{yearGroup.yearTotalBlogs}}</span>
                </div>

                <ul style="display:none;" id="arch_{{yearGroup.yearName}}">
                    <li ng-repeat="monthGroup in yearGroup.months">

                        <div class="monthGroup" ng-click="toggleDisplay('arch_' + yearGroup.yearName + '_' + monthGroup.monthName)">
                            {{monthGroup.monthName}} <span class="badge">{{monthGroup.monthBlogs.length}}</span>
                        </div>

                        <ul style="display:none;" id="arch_{{yearGroup.yearName}}_{{monthGroup.monthName}}">
                            <li>
                                <a ng-repeat="blog in monthGroup.monthBlogs" href="{{blog.url}}">{{blog.title}}</a>
                            </li>
                        </ul>
                    </li>
                </ul>

            </li>
        </ul>
    </div>
</div>

The template is based on bootstrap template component. This template can have a css style sheet for further customization for the look and feel of this template. Here is the listing for the css style sheet.

.blog-archive-panel {
    border-color: #2980B9;
    border-radius: 0;
    border: 1px solid #2980B9;
    color: white;    
}

.blog-archive-panel-heading {
    background-color: #2980B9;
    border: 1px solid #2980B9;
    border-radius: 0;
}

.blog-archive-panel-title {
    font-size: 22px;
}

.blog-archive-panel-body ul {
    margin: 0;
    padding: 0;
    list-style-type: none;
    white-space: nowrap;
}

.blog-archive-panel-body ul li {
    margin: 5px 0 5px 5px;
    list-style-type: none;
}

.blog-archive-panel-body ul li div {
    display: block;
    font-size: 14px;
    cursor: pointer;
    padding: 5px;
}

.blog-archive-panel-body ul li a {
    margin-left: 5px;
    display: block;
    font-weight: bold;
}

.blog-archive-panel-body div.yearGroup {
    background-color: #3c763d;
}

.blog-archive-panel-body div.monthGroup {
    background-color: darkorange;
}

The demo app

This source code include a demo app that you can run to test the directive. The demo app uses express to run an http server in order to serve static files.

If you want to run the demo application then you need to do the following after navigating to the source code directory.

npm install
node demo/app

After that you need to navigate to this url to view the demo: localhost:3001/directiveDemo.html

Comments