3

I'm doing a multi-checkbox form where I have as many as 100 items in my array and a numColumns integer that can range from 1 to 5.

So, if I receive, say, 14 items and 4 columns:

[]item 1  []item 5  []item 9  []item 13
[]item 2  []item 6  []item 10 []item 14  
[]item 3  []item 7  []item 11
[]item 4  []item 8  []item 12

I am looking for a dynamic way of flowing the items into the columns, perhaps using some sort of clever nested repeat.

Short of busting all the items out into their own arrays in the controller, is there a way of using ng-repeat or something to just flow my 50 items into my 4 columns?

I am using angular material, though it is not essential I use their layout. I also have bootstrap.

I can't just do an ng-repeat on the columns, since its not an array of objects, it's just an integer. Unless there's a trick to that.

This is just pseudo-code:

    {{vm.NumberOfColumns.Value}}

    <div class="col-md-{{12/vm.NumberOfColumns.Value}} col-sm-12 multi-column">
        <div id="index_{{item.id}}" class="widget-wrapper multi-check-widget" action="">
            <ul class='multi-check'>
                <li ng-repeat="option in item.response.options">
                    <label><input type="checkbox" name="multichoice" ng-value="option.value">{{option.label}}</label>
                </li>
            </ul>
        </div>
    </div>

I suppose the world wouldn't burn if it flowed them horizontally, if that's more doable:

[]item 1  []item 2  []item 3  []item 4
[]item 5  []item 6  []item 7  []item 8  
[]item 9  []item 10 []item 11 []item 12
[]item 13 []item 14
DaveC426913
  • 2,012
  • 6
  • 35
  • 63
  • have you tried to use clearfix?something like
    data over here
    – Anirudh Mangalvedhekar Dec 22 '16 at 02:19
  • 2
    This is related: http://stackoverflow.com/questions/27211799/angular-ng-repeat-add-bootstrap-row-every-3-or-4-cols – Claies Dec 22 '16 at 02:22
  • Their solution seems to be to bust the item array out into column-level data then make a nested repeat - columns on the outside, items on the inside. Doable but not elegant. – DaveC426913 Dec 22 '16 at 02:24
  • there is also a solution that involves using the `clearfix` class of bootstrap to allow the entire array to flow naturally, but that *definitely* would end up in a horizontal grid. – Claies Dec 22 '16 at 02:29
  • 1
    I *highly* recommend fixing the data in the controller and not trying to do any tricks in the HTML, because there is a **massive** performance impact for doing these kind of calculations in the HTML. Anything done in the HTML has to be re-evaluated every digest cycle, while the controller only has to be evaluated once. – Claies Dec 22 '16 at 02:35
  • Are you still facing problem solving this issue? – Ravi Shankar Bharti Dec 22 '16 at 07:00

2 Answers2

1

You can partition your data in your controller and do nested repeat in the view.

Controller:

Partition your data in chunks.

var partition = function(input, size) {
    var newArr = [];
    for (var i = 0; i < input.length; i += size) {
        newArr.push(input.slice(i, i + size));
        console.log(i);
    }
    return newArr;
}

$scope.numColumns  = 4;//say no.  of columns is 4
$scope.dataPartition =partition($scope.item.response.options,$scope.numColumns) 

View:

Use nested ng-repeat to show how you like it. First ng-repeat should arrange in row and the next one should arrange in a column. this way you will be able to get what you want.

I have written the code snippet in angular-material. you can use whatever you want, the idea remains the same.

<div layout="row" ng-repeat="temp in dataPartition">
    <div layout="column" ng-repeat="option in temp">
         <label><input type="checkbox" name="multichoice" ng-value="option.value">{{option.label}}</label>
    </div>
    <br>

Ravi Shankar Bharti
  • 8,922
  • 5
  • 28
  • 52
0

Yes, I ended up breaking up the data into columns:

        function breakIntoColumns(items, numColumns) {
            var itemsPerColumn = parseInt(Math.ceil(items.length / numColumns));
            var itemsInColumns = [];
            for (var col = 0; col < numColumns; col++) {
                itemsInColumns[col] = [];
                for (var item = 0; item < itemsPerColumn; item++) {
                    if (items.length) { // stop when items array is empty
                        // 'shift' first item off items array, 'push' it to this column
                        itemsInColumns[col].push(items.shift()); 
                    }
                }
            }
            return itemsInColumns;
        };

.

<ul class='multi-check-columns'>
    <li ng-repeat="column in vm.itemsInColumns">
        <ul class='multi-check-items'>
            <li ng-repeat="item in column">
                <label>
                    <input type="checkbox" name="multichoice" ng-model="item.value">
                    &nbsp;{{item.label}}
                </label>
            </li>
        </ul>
    </li>
</ul>

.

.multi-check-columns {
    list-style-type:none;
    width: 100%;
    padding: 0;
}
.multi-check-columns > li {
    display: inline-flex;
}
.multi-check-items {
    list-style-type:none;
    padding: 0 10px 0 0;
}
DaveC426913
  • 2,012
  • 6
  • 35
  • 63