2

My angular is 1.0.8-stable

My objective is to display data in rows of 3.

My html should look like

<div class="table-row">
    <div class="item">item1</div>
    <div class="item">item2</div>
    <div class="item">item3</div>
</div>

My pseudo code is if the $index mod 3 == 0 then I will display <div class="table-row">.

if the $index mod 3 == 2, then I will display </div>.

So far, I have this.

<div ng-repeat='item in my_works.items'>
    <!-- if index mod 3 == 0 show <div>-->
    <!-- if index mod 3 == 2 show </div>-->
</div>

Perhaps I was thinking it in the wrong way as there may be a more efficient way to do this in angularjs?

2
  • first of all, there's ngIf , second of all - you're not the first person trying to show elements in rows of 3. Search SO for relevant questions :) Commented Oct 24, 2013 at 11:13
  • @BenjaminGruenbaum Thank you. But I am using the stable 1.0.8 so no ngIf for me. I have searched SO, so far no questions that have the same setup as mine. Commented Oct 24, 2013 at 11:29

3 Answers 3

3

You can use (key, value) in expression – where key and value can be any user defined identifiers, and expression is the scope expression giving the collection to enumerate.

You can try something like this

<div ng-repeat='(index, item) in my_works.items'> 
   <div class="table-row" ng-show="index % 3 == 0">
   </div>
</div>

Reference

Sign up to request clarification or add additional context in comments.

1 Comment

Note that ng-show will hide the entire div (including contents). So you can't use it to create just the opening part of the div. It'd be nice to have this level of control. But sadly we don't- so this answer just hides every third item
2

Since you can't use ng-if in 1.0.8 here are two variations that solve the problem. They both wrap 3 items into a table-row div

The outer loop counts off in groups of three, so it fires once per outer table-row div. The second approach uses a filter to control the loop range but it should have better performance. The first approach doesn't require a new filter.

Then the inner ng-repeat loops through the 3 items within a row. It uses slice to get just the 3 array items needed for that particular row.

Here's a fiddle with both of the variations working: http://jsfiddle.net/f8D8q/4/

Option 1: Solution without a new filter:

   <div ng-repeat='itemtmp in items|limitTo:(items.length/3)+1'>
        <div class="table-row"> 
            <span ng-repeat='item in items.slice($index*3,($index*3+3))'>
              {{item.name}} - {{$index}}
            </span>
          </div>
   </div>

Option 2: More performant solution using range filter from http://www.yearofmoo.com/2012/10/more-angularjs-magic-to-supercharge-your-webapp.html#more-about-loops

   <div ng-repeat="n in [] | range:(items.length/3)+1">
        <div class="table-row">
            <span ng-repeat='item in items.slice($index*3,($index*3+3))'>
                {{item.name}} - {{$index}}
            </span>
        </div>
    </div>

and the associated range filter:

 app.filter('range', function () {
    return function (input, total) {
        total = parseInt(total);
        for (var i = 0; i < total; i++) {
            input.push(i);
        }
        return input;
    };
});

Both are tested (down to 1.0.2) and work.

2 Comments

I pick this answer and option 2. This is an excellent answer. I don't understand why it got -1 vote.
I have another issue with sending jsonp requests from angularjs. Care to help? stackoverflow.com/q/19603757/80353
1
  1. Convert your flat list of items to a list of lists of 3 items.
  2. Iterate over the list of lists.
<div class="table-row" ng-repeat="list in listOfLists">
    <div class="item" ng-repeat="item in list">
      {{ item }}
    </div>
</div>

If you already have a list, items, you could add a filter chunked and replace listOfLists with items|chunked:3, assuming you implement chunked something like this:

app.filter('chunked', function(){
    return function(list, chunkSize){
        var chunks = [];
        angular.forEach(list, function(element, i){
            if(i % chunkSize === 0){
                 currentChunk = [];
                 chunks.push(currentChunk);
            }
            currentChunk.push(element);
        });
        return chunks;
    };
});

I think that matches what you are trying to do; here's a plunker: http://plnkr.co/edit/3h7JprbXFVwnNZErj7hl

I didn't get a chance to test with old Angular though.

1 Comment

This caused "10 $digest() iterations reached. Aborting!" for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.