Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Horizontal ng-repeat(er) with new row breaks

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;
}
like image 542
jnthnjns Avatar asked Sep 18 '13 14:09

jnthnjns


7 Answers

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.

like image 60
yshaool Avatar answered Sep 23 '22 17:09

yshaool


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"

like image 45
EnigmaRM Avatar answered Sep 24 '22 17:09

EnigmaRM


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.

like image 39
Saud Alfadhli Avatar answered Sep 26 '22 17:09

Saud Alfadhli


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;
}
like image 28
Jonathan Hamilton Avatar answered Sep 25 '22 17:09

Jonathan Hamilton


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...

like image 27
Kcats Wolfrevo Avatar answered Sep 27 '22 17:09

Kcats Wolfrevo


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>  
like image 28
Suresh Bala Avatar answered Sep 27 '22 17:09

Suresh Bala


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>
like image 41
Marshee Avatar answered Sep 27 '22 17:09

Marshee