2

Edited to include angular code (for illustration purposes only)

I've been trying to find away in AngularJS to auto wrap columns in rows after n columns whilst not affecting the index.

<div class="row">
{{for (var i = 0; i < list.length; i++ )  {   }}
<div class="col-4">list[0].name</div>
{{  }  }}

This is how it'd be done in PHP below.

In short:

<div class="row">
<?php 

 $collection = array( 'item1', 
                      'item2',
                      'item3', 
                      'item4',
                      'item5',
 );

 for($i = 0; $i < count($collection); $i++ ) : ?>

    <div class="col-4">
       <?php echo $collection[$i] ?>
    </div>

<?php if(($i + 1) % 3 === 0) :?>

</div> <!-- close row -->
<div class="row"><!-- open new row -->

<?php endif ?>
<?php endfor ?>

</div> <!-- close final row -->

I know it can be done within a controller and pushed back into the DOM within a link function, but that just seems horrible. I'm sure I must be missing something, but conditionally adding the closing div before the opening one is proving tricky for me.

P.S. I considered doing the example using Underscore.js, but felt this would be a little more universal.

Know Pledge
  • 31
  • 1
  • 7
  • 1
    you asked a question about how to do this in angularjs, then posted an example in php. where is the attempt you made in angular? – Claies Sep 21 '15 at 23:57
  • Conditionally closing /adding HTML tags is what seems horrible. Structure your data in JavaScript and let Angular bind this data to structured HTML elements. – ThiagoPXP Sep 21 '15 at 23:59
  • This whole thing is a CSS problem anyway; if you're trying to wrap columns, use a grid framework that handles it automatically, like Bootstrap. – Carl Bussema Sep 22 '15 at 00:01
  • numerous ways to do this ... try one at least – charlietfl Sep 22 '15 at 00:07
  • Wow wasn't expecting the responses so soon. @ThiagoPXP I know there are ways to do it within the controller by mutating the data there, however I was hoping to retain access to the index this way. Is it better to just mutate the data in the controller and calculate the index? – Know Pledge Sep 22 '15 at 00:34
  • @Claies Do you really want me to post the one way I 100% don't what to do? It's a simple question with what I'm aiming for completely spelt out. Well other than my omission that I didn't want to have to recalculate the index. – Know Pledge Sep 22 '15 at 00:35
  • @Carl Bussema, thanks for the reply. I agree, but I'm using Ionic built in flex-grid which doesn't seem to wrap columns unless I'm missing something? – Know Pledge Sep 22 '15 at 00:40
  • You will find better answers if you present your attempt and others help you fix it than if you give a problem statement and ask for code to be given to you – Claies Sep 22 '15 at 00:52
  • Thank you for your response Claies, I understand how my question may have appeared "do my homework for me". I'm still new to asking questions here. The fact that this is my second question hopefully shows I do know how to search :-). I felt my attempts would likely confuse/over complicate the question when I'm sure most would see it and know exactly what I was hoping to do. – Know Pledge Sep 22 '15 at 01:02
  • For anyone who doesn't require the index a good bet is here http://stackoverflow.com/questions/21644493/how-to-split-the-ng-repeat-data-with-three-columns-using-bootstrap – Know Pledge Sep 22 '15 at 01:04
  • @KnowPledge, then set your row via CSS to `flex-wrap: wrap;` and set your columns as `class="col-33"` – Carl Bussema Sep 22 '15 at 01:15
  • the way you rendered this is a bit odd as well, I would recommend using `ng-repeat` instead of using a `for` iterator in an expression `{{ }}`. – Claies Sep 22 '15 at 01:28
  • I was also working on a potential solution if using `flex-wrap: wrap;` didn't work, but I'm glad that it worked for you. – Claies Sep 22 '15 at 01:29
  • I'd still love to know the solution as I'm sure it'll help others. Just so you know you've been as kind as can be already! – Know Pledge Sep 22 '15 at 01:36
  • @Claies, I guess it was kind of my question, can something like a for statement be used in an expression or anywhere else (like in a self created directive ng-for). I understand this is what the ng-repeat is for but I can only imagine problems without fully structured HTML – Know Pledge Sep 22 '15 at 01:43
  • the first, key point to know about `ng-repeat` is that the element this directive is added to is the one that gets repeated over and over (along with it's closing statement); it's easy to get this confused and think that it's the contents of the element only. – Claies Sep 22 '15 at 02:05

3 Answers3

1

(Reposted from my comments above.) This is a CSS problem, not a PHP or Angular problem, although there are solutions in those.

Since you're using a flex-box framework, you need to set your rows to flex-wrap: wrap (via a CSS file preferably) and define your columns as 33.33333% wide; which in Ionic, means class='col-33'

Carl Bussema
  • 1,684
  • 2
  • 17
  • 35
  • Thank you Carl Bussema, a simple flex-wrap: wrap done the trick. I really need to do a flex-box tut. Coming from the "old" CSS ways of doing things doesn't help. Gives me hope for the future. – Know Pledge Sep 22 '15 at 01:26
  • sorry to bother you, but would you say templating like I had above and that of Underscore doesn't have a place in Angular? And a final pesky question which I fully respect you for ignoring. Does flex-box also have a magic property for centering any incomplete rows i.e. a grid of 3 which has only 2 in the last row? – Know Pledge Sep 22 '15 at 01:32
  • Eh, I don't like to answer primarily opinion-based questions, and I'm no expert on underscore or Angular. As for the other, try .row:last-child { justify-content: center; } but I haven't tested that. – Carl Bussema Sep 22 '15 at 01:38
  • And again that worked! Argh, I tried justify-content: center; earlier and it laughed at me! I appreciate your stance regarding opinion-based questions. Guess I'm just trying to solidify the "better" way to using Angular and friends. Anyway because of you, I can sleep now... seriously thank you. – Know Pledge Sep 22 '15 at 01:50
0

This is an example of a way that you could accomplish something similar to the output you wrote in php, which uses ng-repeat, ng-if, and the special property of ng-repeat, $index. I don't really recommend this approach, since it generates many empty elements, but it can be used in a pinch, and shows a bit of what ng-repeat is capable of.

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

app.controller('MainCtrl', function($scope) {
  $scope.collection = [
    'item1',
    'item2',
    'item3',
    'item4',
    'item5',
    'item6',
    'item7',
    'item8'
  ];
});
<body ng-controller="MainCtrl">
  <div ng-repeat="item in collection">
    <div class="row" ng-if="$index%3==0">
      <div class="col-xs-4">
        {{collection[$index]}}
      </div>
      <div class="col-xs-4">
        {{collection[$index+1]}}
      </div>
      <div class="col-xs-4">
        {{collection[$index+2]}}
      </div>
    </div>
  </div>
</body>

http://plnkr.co/edit/oytUy9rOkHmbFYowiINA?p=preview

as a comparison, here is what the code should look like when using flex:wrap:

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

app.controller('MainCtrl', function($scope) {
  $scope.collection = [
    'item1',
    'item2',
    'item3',
    'item4',
    'item5',
    'item6',
    'item7',
    'item8'
  ];
});
<body ng-controller="MainCtrl">
  <div class="row" style="flex-wrap : wrap;">
    <div class="col-33" ng-repeat="item in collection">
      {{item}}
    </div>
  </div>
</body>

http://plnkr.co/edit/ZnzVJxQPzrxwSbes06RF?p=preview

Claies
  • 22,124
  • 4
  • 53
  • 77
  • Thanks for the response. Yeah I came out with empty divs too. I see the value in posting attempts. Thank you for your time, I'll be sure to post my plunks regardless in future. – Know Pledge Sep 22 '15 at 02:09
0

Turns out using flex-wrap: wrap; (as suggested by Carl Bussema) has no effect in Ionic Viewer and the iOS emulator (I haven't tested on an actually device yet, however I'm expected the same results).

To solve this I've gone back to some old code which was similar to Claies (found above). To avoid the empty divs add an ng-if testing for whether the length of the collection has reached the $indexed item.

<body ng-controller="MainCtrl">
    <div class="row" ng-repeat="item in collection" ng-if="$index % 3 === 0">
       <div class="col col-33" ng-if="$index < collection.length">
           {{collection[$index]}}
       </div>
       <div class="col col-33" ng-if="$index + 1 < collection.length">
           {{collection[$index + 1]}}
       </div>
       <div class="col col-33" ng-if="$index + 2 < collection.length">
           {{collection[$index + 2]}}
       </div>
    </div>
</body>
Know Pledge
  • 31
  • 1
  • 7