Working with Bootstrap and AngularJS, is there a way to ng-repeat
horizontally with a new row for every set amount of elements?
I have been playing around with ng-class
to accomplish this Fiddle, but the problem is that I can't get the float left divs within the initial row div... Any thoughts, am I not thinking of something or would this best be done with a Directive?
Here is my code (live example in the above fiddle link):
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<div ng-repeat="num in numbers"
ng-class="{'row': ($index)%2==0, 'col-md-6': ($index)%2!=0}">
<div ng-class="{'col-md-6': ($index)%2==0}">
{{num}}
</div>
</div>
</div>
</body>
var myApp = angular.module('myApp', [])
.controller('MyCtrl', function ($scope) {
$scope.numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
});
.row {
clear: both;
width: 100%;
border: 1px solid red;
}
.col-md-6 {
width: 50%;
float: left;
border: 1px solid blue;
}
If you are working with Bootstrap 3 and AngularJS you can declare a new filter that will return one array of sub array slices and then do two ng-repeat.
It will look like that:
<div class="row" ng-repeat="row in filtered = (arr | splitArrayFilter:3)">
<div class="col-md-4" ng-repeat="n in row">
<h3>{{n}}</h3>
</div>
</div>
app.filter('splitArrayFilter', function() {
return function(arr, lengthofsublist) {
if (!angular.isUndefined(arr) && arr.length > 0) {
var arrayToReturn = [];
var subArray=[];
var pushed=true;
for (var i=0; i<arr.length; i++){
if ((i+1)%lengthofsublist==0) {
subArray.push(arr[i]);
arrayToReturn.push(subArray);
subArray=[];
pushed=true;
} else {
subArray.push(arr[i]);
pushed=false;
}
}
if (!pushed)
arrayToReturn.push(subArray);
console.log(JSON.stringify(arrayToReturn));
return arrayToReturn;
}
}
});
You can Find it on Plunker here: http://plnkr.co/edit/rdyjRtZhzHjWiWDJ8FKJ?p=preview for some reason the view in plunker does not support bootstrap 3 columns but if you open it in embedded view or in browsers you can see that it works.
It was clever what you were doing with ng-class
. I hadn't ever thought of using %2
within the expression there.
But for future reference, there is a slightly easier way to accomplish that: ng-class-even
and ng-class-odd
. It does the same thing as what you were doing, but just a bit cleaner:
<div ng-repeat="num in numbers" ng-class-even="'md-col-6'" ng-class-odd="'row'">
{{num}}
</div>
But this doesn't resolve your problem. If I understand you correctly, you want a row, with two columns within that row. The easiest way I could think of is to split up the arrays. Put the repeat on the div
, then have 2 span
within the div
. I think one of the issues that you had originally, is that you were repeating a single div
, and trying to treat that block
element as an inline
Controller
myApp.controller('MyCtrl', function ($scope) {
$scope.evens = ["2","4","6","8","10","12","14"];
$scope.odds = ["1","3","5","7","9","11","13"];
});
HTML
<div ng-controller="MyCtrl">
<div ng-repeat="odd in odds" class="row">
<span class="span3">{{odd}}</span>
<span class="span2">{{evens[$index]}}</span>
</div>
</div>
Fiddle
Being that you're using version 1.1.5, that also opens you up to a new directive: ng-if
! You could also use ng-switch
to do some conditional logic displays.
You didn't include bootstrap in your fiddle, and for some reason I can't get jsFiddle to display bootstrap. So I created some temp CSS classes that would somewhat resemble bootstraps class="span"
No need to add .row class .. I did this:
HTML:
<div ng-repeat="product in allProducts">
<div class="my-col-50">
<h1>{{product.title}}</h1>
</div>
</div>
CSS:
.my-col-50{float:left;width:50%;}
and it's work like a charm.
Although this isn't the "proper" way of doing this, there is a way to achieve this using CSS.
For example, this is for a 3 column layout:
HTML:
<div class="row">
<div ng-repeat="(key, pod) in stats.pods" class="pod-wrap">
<div ng-if="objectCheck(pod) == false" class="col-md-4 col-sm-4 pod">
<div>
<h2 ng-bind="key"></h2>
<p class="total" ng-bind="pod | number"></p>
</div>
</div>
<div ng-if="objectCheck(pod) == true" class="col-md-4 col-sm-4 pod">
<div>
<h2 ng-bind="key"></h2>
<div ng-repeat="(type, value) in pod track by $index">
<p class="status"><% type %> <small><% value %></small></p>
</div>
</div>
</div>
</div>
</div>
CSS:
.pod-wrap:nth-of-type(3n):after {
display: table;
content: '';
clear: both;
}
I tried two of the suggestions given here... the one by yshaool works fine but like i commented on it give me that infinite loop error.
Then I tried something like below:
<div class="row" ng-repeat="row in split($index, 3, row.Attempts)">
<div class="col-md-4" ng-repeat="attempt in row">
<div>Attempt {{row.AttemptNumber}}</div>
<div>{{row.Result}}</div>
</div>
</div>
and the function:
$scope.split = function (index, length, attempts) {
var ret = attempts.slice(index * length, (index * length) + length);
console.log(JSON.stringify(ret));
return ret;
}
was going somewhere with that when i realized that it could be as simple as
<div ng-repeat="attempt in row.Attempts">
<div class="col-md-4">
<div>Attempt {{attempt.AttemptNumber}}</div>
<div>{{attempt.Result}}</div>
</div>
</div>
using "col-md-4" does the trick as I only need to split using three columns per row.. (let bootstrap do the work!) anyway the other answers here were really useful...
Depending upon the number of columns that you need in your template, create chunks of the original data source in your controller.
$scope.categories = data //contains your original data source;
$scope.chunkedCategories = [] //will push chunked data into this;
//dividing into chunks of 3 for col-4. You can change this
while ($scope.categories.length > 0)
$scope.chunkedCategories.push($scope.categories.splice(0, 3));
In your template you can now do the following
<div class="row" ng-repeat="categories in chunkedCategories">
<div class="col-xs-4" ng-repeat="category in categories">
<h2>{{category.title}}</h2>
</div>
</div>
My approach was to use the $index variable, which is created and updated by AngularJS within an ng-repeat directive, to trigger a call to the CSS clearfix hack which, in turn, resets to a new row.
I am using the following versions: AngularJS 1.5.5 and Bootstrap 3.3.4
<!-- use bootstrap's grid structure to create a row -->
<div class="row">
<!-- Cycle through a list: -->
<!-- use angular's ng-repeat directive -->
<div ng-repeat="item in itemList">
<!-- Start a new row: -->
<!-- use the css clearfix hack to reset the row -->
<!-- for every item $index divisible by 3. -->
<!-- note that $index starts at 0. -->
<div ng-if="$index % 3 == 0" class="clearfix"></div>
<!-- Create a column: -->
<!-- since we want 3 "item columns"/row, -->
<!-- each "item column" corresponds to 4 "Bootstrap columns" -->
<!-- in Bootstrap's 12-column/row system -->
<div class="col-sm-4">
{{item.name}}
</div>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With