1

enter image description here

Currently I have a list which I populate using ng-repeat and use columns of width 6. However, the data I'm iterating through is alphabetically sorted and I'd like the list to populate alphabetically going downwards, while still retaining the aesthetic of having two evenly-stacked columns. Is this able to be done using bootstrap without data preprocessing?

For example, in the example above, it is alphabetical left to right and top down. I'd like it to be alphabetical going downwards, and the second column continues on from the first column with the last half of the data.

Here is some stripped down code:

<div class="col-md-12 col-sm-12 col-xs-12" ng-repeat="topLayerObject in objectArray | findParentLevelObjects">
 <div class="col-md-12 col-sm-12 col-xs-12">
  <button type="button" class = "btn btn-primary btn-block">{{topLayerObject.name}}</button>
 </div>
 <div style="padding-left:5px">
  <div class="col-md-6 col-sm-6 col-xs-6 lowPadding" ng-repeat="questionObj in objectArray | findChildLevelObjects">
   <label ng-if="!requiresInput(questionObj)">
     <input type="checkbox">{{questionObj.name}}
   </label>
  </div>
 </div>
</div>

Edit: To be clear, every object is in the same flattened array so children and parents are not separated from each other nor are they logically grouped. That's why a vertical population is so attractive to me - I would have to add additional data structures or loop over the data several times to deal with processing these nested columns just to count them. Is there some kind of flexbox which can keep items at an even level but stretch vertically as needed?

user1066886
  • 202
  • 3
  • 12

1 Answers1

1

Repeat your list twice but limit which items are displayed in each using limitTo. Use HTML/CSS for making the lists side-by-side. I've used 2 Bootstrap columns in the snippet below.

You can work out how many items should be in the left column using Math.ceil(items.length / 2); If you have an even number of items it will split evenly otherwise it will round up so there is 1 more item in the left list.

1st column:

<div ng-repeat="item in items | limitTo : breakpoint">

2nd column (negative limitTo will start from the end of the list):

<div ng-repeat="item in items | limitTo : breakpoint - items.length">

var app = angular.module("app", []);

app.controller("controller", function($scope) {
  $scope.objectArray = [{
      name: "Odd number of items",
      items: ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
    },
    {
      name: "Even number of items",
      items: ["A", "B", "C", "D", "E", "F"]
    }
  ];

  // Calculate where to break the list in 2. If you know the length of your list isn't going to change I would change this to a variable instead of calling the function twice each digest cycle
  $scope.getBreakPoint = function(items) {
    return Math.ceil(items.length / 2); // this will round up if the number of items is odd
  };

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<div ng-app="app" ng-controller="controller">
  <div class="col-md-12 col-sm-12 col-xs-12" ng-repeat="topLayerObject in objectArray">
    <div class="col-md-12 col-sm-12 col-xs-12">
      <button type="button" class="btn btn-primary btn-block">{{topLayerObject.name}}</button>
    </div>
    <div style="padding-left:5px">
      <div class="col-md-6 col-sm-6 col-xs-6 lowPadding">
        <div ng-repeat="item in topLayerObject.items | limitTo : getBreakPoint(topLayerObject.items)">
          <label>
              <input type="checkbox">{{item}}
       </label>
        </div>
      </div>
      <div class="col-md-6 col-sm-6 col-xs-6 lowPadding">
        <!-- Use a negative limitTo will start from the end of the list -->
        <div ng-repeat="item in topLayerObject.items | limitTo : getBreakPoint(topLayerObject.items) - topLayerObject.items.length">
          <label>
            <input type="checkbox">{{item}}
       </label>
        </div>
      </div>
    </div>
  </div>
</div>
Jaydo
  • 1,830
  • 2
  • 16
  • 21
  • Unfortunately, everything is in the same array and the items are not separated from each other nor their parent. That's why a vertical population is so attractive to me - I would have to add additional data structures or loop over the data several times to deal with processing these nested columns just to count them. Is there some kind of flexbox which can keep items at an even level but stretch vertically as needed? – user1066886 Mar 27 '17 at 23:03
  • @user1066886 If you're after a CSS only solution have a look at this [answer](http://stackoverflow.com/a/12332549/3894163) to another question. – Jaydo Mar 27 '17 at 23:48
  • It seems as though that uses fixed with columns. I'm looking for something a bit more responsive and data driven, to deal with data of varying input numbers such as the above example – user1066886 Mar 27 '17 at 23:56
  • @user1066886 The columns aren't fixed. Try removing all the CSS except the column-count properties. [Fiddle](https://jsfiddle.net/L1k8sshn/) – Jaydo Mar 28 '17 at 00:29
  • This seems to work extremely well BUT does not seem to work with bootstrap. This is problematic as if the display becomes too small, it is beneficial to have the checkboxes take up an entire line. In some displays, the word gets clipped and can't be displayed fully. Do you have any recommendations? A messy workaround would be to make my column container which contains the column-count a conditional based on size, and similarly give conditional classes to the subobjects but this seems unoptimal. If you edit your original response, I will accept it as the answer. – user1066886 Mar 28 '17 at 00:51
  • I've found that if I wrap my columnContainer class which holds the column-count in a \@media query, it works well. \@media (min-width:450px){ .columnContainer { -webkit-column-count: 2; -moz-column-count: 2; column-count:2; } } If you edit your answer, I will accept it. – user1066886 Mar 28 '17 at 01:00
  • @user1066886 I won't edit my answer because I've just copied it from another answer. Make sure to upvote them. – Jaydo Mar 28 '17 at 01:04