1

My code repeats posts from the API and shows 9 posts in a row. My goal is to create a grid - 3 rows with 3 posts in each one. The solution I tried doesn't work. I also tried 'clearfix', but with no success. Does anyone know how to make this work?

Here's the code:

var myApp = angular.module('myApp', ['ngRoute', 'ui.bootstrap']);

    myApp.config(function ($routeProvider) {
        $routeProvider.when('/', {
            templateUrl: 'allposts.htm',
            controller: 'PostsController'
        }).when('/post', {
            templateUrl: 'post.htm',
            controller: 'PostController'
        }).when('/addpost', {
            templateUrl: 'addpost.htm',
            controller: 'AddController'
        }).otherwise({
            redirectTo: '/'
        });
    });

    myApp.controller('PostsController', function ($scope) {
    });

    myApp.controller('PostController', function ($scope) {
    });

    myApp.controller('AddController', function ($scope) {
    });


    myApp.controller('controller', function ($scope, $http) {
        $scope.title = "My app";
        $http({
            method: 'GET',
            url: "http://jsonplaceholder.typicode.com/posts"
        }).then(function (response) {
            $scope.posts = response.data;
            $scope.post = response.data[0];
            $scope.viewby = 9;
            $scope.totalItems = $scope.posts.length;
            $scope.currentPage = 1;
            $scope.itemsPerPage = $scope.viewby;
            $scope.maxSize = 5;
        });

        $scope.setPage = function (pageNo) {
            $scope.currentPage = pageNo;
        };

        $scope.setItemsPerPage = function (num) {
            $scope.itemsPerPage = num;
            $scope.currentPage = 1; //reset to first page
        };

        $scope.getRowClass = function (index) {
            if (index % 3 === 0) {
                return "row";
            }
        };
    });
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>App</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js'></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-route.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-animate.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.1.3/ui-bootstrap-tpls.js"></script>
</head>

<body layout="column" ng-app="myApp" ng-cloak ng-controller="controller">
    <h1>{{title}}</h1>
    <a href="#post">Post</a> |
    <a href="#addpost">Add a post</a>
    <script type="text/ng-template" id="allposts.htm">
        View
        <select ng-model="viewby" ng-change="setItemsPerPage(viewby)">
            <option>9</option>
            <option>18</option>
            <option>36</option>
            <option>100</option>
        </select> posts
        <div layout="row">
            <div class="col-sm-4" ng-class="getRowClass($index)"
                 ng-repeat="post in posts.slice(((currentPage-1)*itemsPerPage), ((currentPage)*itemsPerPage))">

                <a href="#post">{{post.title}}</a>
                <hr>
                <p>{{post.body}}</p>
            </div>
            <div class="clearfix" ng-if="$index % 3 == 0"></div>

        </div>
        <ul uib-pagination total-items="totalItems" ng-model="currentPage" class="pagination-sm"
            items-per-page="itemsPerPage"></ul>

    </script>
    <script type="text/ng-template" id="post.htm">
            </script>
    <script type="text/ng-template" id="addpost.htm">
            </script>
    <div ng-view></div>
</body>
</html>

2
  • 1
    I think you are declaring you setPage, setItemsPerPage and getRowClass functions in the then function of the $httpService. Commented Sep 7, 2016 at 11:34
  • Thanks, you're right, but after correcting it doesn't work either Commented Sep 7, 2016 at 11:38

2 Answers 2

2

The problem is that you are mixing Angular Material with Bootstrap classes. The following example only uses the Bootstrap.

The next problem is that when you make a grid for example if you are use 6 divisions with .col-xs-4 class in a single .row element then those will adjust automatically only if the height of all 6 divisions are same. Otherwise, the view will be messed up like in your example.

To fix this issue, you have to create multiple .row element so for this either you can write a directive to do it in the view itself or collate the list before passing it to the view.

The following example is doign it in the controller itself (i.e. before passing to the view):

// Helper function to collate a list
Array.prototype.collate = function(collateSize) {
    var collatedList = [];

    if (collateSize <= 0) {
        return [];
    }
    angular.forEach(this, function(item, index) {
        if (index % collateSize === 0) {
            collatedList[Math.floor(index / collateSize)] = [item];
        } else {
            collatedList[Math.floor(index / collateSize)].push(item);
        }
    });

    return collatedList;
};

var myApp = angular.module('myApp', ['ngRoute', 'ui.bootstrap']);

myApp.config(function($routeProvider) {
    $routeProvider.when('/', {
        templateUrl: 'allposts.htm',
        controller: 'PostsController'
    }).when('/post', {
        templateUrl: 'post.htm',
        controller: 'PostController'
    }).when('/addpost', {
        templateUrl: 'addpost.htm',
        controller: 'AddController'
    }).otherwise({
        redirectTo: '/'
    });
});

myApp.controller('PostsController', function($scope) {});

myApp.controller('PostController', function($scope) {});

myApp.controller('AddController', function($scope) {});


myApp.controller('controller', function($scope, $http) {
    $scope.title = "My app";
    $http({
        method: 'GET',
        url: "http://jsonplaceholder.typicode.com/posts"
    }).then(function(response) {
        $scope.posts = response.data;
        $scope.viewby = 9;
        $scope.totalItems = $scope.posts.length;
        $scope.currentPage = 1;
        $scope.itemsPerPage = $scope.viewby;
        $scope.maxSize = 5;
        $scope.collatedPosts = getCollatedPosts($scope.posts);
    });

    function getCollatedPosts(posts) {
        if (!posts) {
            return [];
        }

        var paginatedPosts = posts.slice((($scope.currentPage - 1) * $scope.itemsPerPage), (($scope.currentPage) * $scope.itemsPerPage));
        return paginatedPosts.collate(3);
    }

    $scope.setPage = function(pageNo) {
        $scope.currentPage = pageNo;
    };

    $scope.setItemsPerPage = function(num) {
        $scope.itemsPerPage = num;
        $scope.currentPage = 1; //reset to first page
        $scope.collatedPosts = getCollatedPosts($scope.posts);
    };

    $scope.pageChanged = function(currentPage) {
        $scope.currentPage = currentPage;
        $scope.collatedPosts = getCollatedPosts($scope.posts);
    };
});
.row {
  /* Using red border just for understanding */
  border-bottom: 2px solid red;
  margin-bottom: 10px;
  margin-top: 10px;
}
<html>

<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js'></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-route.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-animate.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.1.3/ui-bootstrap-tpls.js"></script>
</head>

<body layout="column" ng-app="myApp" ng-cloak ng-controller="controller">
    <h1>{{title}}</h1>
    <a href="#post">Post</a> |
    <a href="#addpost">Add a post</a>
    <script type="text/ng-template" id="allposts.htm">
        View
        <select ng-model="viewby" ng-change="setItemsPerPage(viewby)">
            <option>9</option>
            <option>18</option>
            <option>36</option>
            <option>100</option>
        </select>posts
        <div class="row" ng-repeat="collatedPostList in collatedPosts">
            <div class="col-xs-4" ng-repeat="post in collatedPostList">

                <a href="#post">{{post.title}}</a>
                <hr>
                <p>{{post.body}}</p>
            </div>

        </div>
        <ul uib-pagination total-items="totalItems" ng-model="currentPage" class="pagination-sm"
            items-per-page="itemsPerPage" ng-change="pageChanged(currentPage)"></ul>

    </script>
    <script type="text/ng-template" id="post.htm">
  </script>
    <script type="text/ng-template" id="addpost.htm">
  </script>
    <div ng-view></div>
</body>

</html>

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, it makes a wonderful grid, but the pagination stopped working.
Yup! was fixing that. That's a scope issue. Check now the updated answer.
Run the example in full page to view properly. I've changed the border color to red for more clarity.
0

You may need to add an ng-repeat to your "row" div to properly calculate the total number of rows needed based on your variables. You don't actually have to output anything with an ng-repeat, just use the array to determine the desired number of elements. Then adjust your current ng-repeat to properly slice the array from the correct starting position for the number of columns desired.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.