skip to Main Content

I keep running into this problem and haven’t found a good solution that doesn’t cause layout issues. What’s the best way to display an array of items, sorted alphabetically, in columns? I’m using ng-repeat to iterate over an array and display a checkbox for each item. I want the data to be displayed in n columns, alphabetically i.e., not alphabetically in rows.

alphabetically in colums

|item a| |item d| |item g|
|item b| |item e| ...
|item c| |item f| ...

current implementation – alphabetically in rows

  <div class="checkbox col-xs-12 col-sm-12 col-md-3 col-lg-3" ng-repeat="user in user.results | orderBy:'lastName' track by user.id">
    <input id="{{ user.id }}" type="checkbox">
    {{ user.lastName }}, {{ user.firstName }}
    <label for="{{ user.id }}" class="pull-left checkbox-label"></label>
  </div>

Edit

I originally went with the dynamic bootstrap method but this actually screwed up the checkbox behavior i.e., clicking a checkbox resulted in the incorrect checkbox being checked. I’m trying fix this using flexbox but I haven’t used it before and don’t understand how to dynamically change the column count without having to set a fixed height on the flex container. I would like to have one column on small/extra small screens and three columns for medium/large screens.

.flex-box {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}
.flex-item {
  background: green;
    width: 33%;
}

/* Small screens */
@media all and (max-width: @container-tablet) {
  .flex-item {
    width: 100%;
  }
}

  <div class="flex-box">
    <div class="flex-item" ng-repeat="country in region.countries | orderBy:'name' track by $index">
      <input id="{{ country.isoCode }}" checklist-model="vm.selectedCountries.value[region.name]" checklist-value="country" type="checkbox" ng-change="vm.setRegionCountry(region, country, checked)">
      <label for="{{ country.isoCode }}" class="pull-left checkbox-label"></label>
      <span>{{ country.name | limitTo:17 }}{{country.name.length > 17 ? '...' : ''}}</span>
    </div>
  </div>

Solution

.flex-box {
  display: flex;
  flex-flow: column wrap;
}

/* Small screens */
@media all and (min-width: @screen-sm-min) {
    .flex-box {
        max-height: 375px;
    }
}
/* Medium screens */
@media all and (min-width: @screen-md-min) {
    .flex-box {
        max-height: 550px;
    }
}
/* Large screens */
@media all and (min-width: @screen-lg-min) {
    .flex-box {
        max-height: 375px;
    }
}

3

Answers


  1. You could do this without bootstrap using columns. See this fiddle: https://jsfiddle.net/ojzdxpt1/1/

    #wrapper {
        column-count:3;
        -webkit-column-count:3;
        -moz-column-count:3;
    }
    .col {
      background:#ccc;
      border:1px solid #000;
    }
    

    #wrapper contains each repeater. See more about css columns

    Login or Signup to reply.
  2. <style>
    .flex-box {
            height: 100px;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            flex-wrap: wrap;
        }
        .flex-item {
                background: green;
                text-align: center;
        }
    </style>
    <div class="container">
        <div class="row">
            <div class="col-xs-12">
                <div class="flex-box">
                    <div class="flex-item" ng-repeat="user in user.results | orderBy:'lastName'">{{user.id}}</div>
                </div>
            </div>
        </div>
    </div>
    

    Using CSS flexbox you can dynamically add as many column as required for your data set https://css-tricks.com/snippets/css/a-guide-to-flexbox/

    Login or Signup to reply.
  3. You can tweak little bit as below if you want to use with bootstrap. Otherwise you can use either flex-box or column-count.

    var app = angular.module('app', []);
    app.controller('TestController', function($scope){
      $scope.fixedColumn = 3;
      
      $scope.getColumns = function(){
        return new Array($scope.fixedColumn);
      };
      
      $scope.getColumnWidth = function(){
        return Math.floor(12 / $scope.fixedColumn);
      };
      
      $scope.getRowCount = function(){
        return Math.ceil($scope.user.results.length / $scope.fixedColumn);
      };
      
      $scope.user = {
        results: [
          {
            id: 1,
            firstName: 'FirstName1',
            lastName: 'LastName1'
          },
          {
            id: 2,
            firstName: 'FirstName2',
            lastName: 'LastName2'
          },
          {
            id: 3,
            firstName: 'FirstName3',
            lastName: 'LastName3'
          },
          {
            id: 4,
            firstName: 'FirstName4',
            lastName: 'LastName4'
          },
          {
            id: 5,
            firstName: 'FirstName5',
            lastName: 'LastName5'
          },
          {
            id: 6,
            firstName: 'FirstName6',
            lastName: 'LastName6'
          },
          {
            id: 7,
            firstName: 'FirstName7',
            lastName: 'LastName7'
          },
          {
            id: 8,
            firstName: 'FirstName8',
            lastName: 'LastName8'
          }
        ]
      };
    });
    
    angular.bootstrap(document, ['app']);
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <div class="container" ng-controller="TestController">
    <div class="row" ng-repeat="u in user.results | orderBy:'lastName' track by u.id" ng-init="pIndex=$index" ng-if="$index < getRowCount()">
      <div ng-repeat="col in getColumns() track by $index" ng-init="usr = user.results[pIndex + ($index * getRowCount())]" ng-class="'col-xs-'+ getColumnWidth() + ' col-sm-'+ getColumnWidth() + ' col-md-'+ getColumnWidth()" ng-if="user.results.length > (pIndex + ($index * getRowCount()))">
        <input id="{{ usr.id }}" type="checkbox">
        {{ usr.lastName }}, {{ usr.firstName }}
        <label for="{{ usr.id }}" class="pull-left checkbox-label"></label>
      </div> 
     </div>
     </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search