123

I am using ng-repeat with my code I have 'n' number of text box based on ng-repeat. I want to align the textbox with three columns.

this is my code

<div class="control-group" ng-repeat="oneExt in configAddr.ext">
    {{$index+1}}. 
    <input type="text" name="macAdr{{$index+1}}" 
           id="macAddress" ng-model="oneExt.newValue" value=""/>
</div>
m59
  • 43,214
  • 14
  • 119
  • 136
kuppu
  • 1,264
  • 2
  • 9
  • 10

21 Answers21

257

The most reliable and technically correct approach is to transform the data in the controller. Here's a simple chunk function and usage.

function chunk(arr, size) {
  var newArr = [];
  for (var i=0; i<arr.length; i+=size) {
    newArr.push(arr.slice(i, i+size));
  }
  return newArr;
}

$scope.chunkedData = chunk(myData, 3);

Then your view would look like this:

<div class="row" ng-repeat="rows in chunkedData">
  <div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>

If you have any inputs within the ng-repeat, you will probably want to unchunk/rejoin the arrays as the data is modified or on submission. Here's how this would look in a $watch, so that the data is always available in the original, merged format:

$scope.$watch('chunkedData', function(val) {
  $scope.data = [].concat.apply([], val);
}, true); // deep watch

Many people prefer to accomplish this in the view with a filter. This is possible, but should only be used for display purposes! If you add inputs within this filtered view, it will cause problems that can be solved, but are not pretty or reliable.

The problem with this filter is that it returns new nested arrays each time. Angular is watching the return value from the filter. The first time the filter runs, Angular knows the value, then runs it again to ensure it is done changing. If both values are the same, the cycle is ended. If not, the filter will fire again and again until they are the same, or Angular realizes an infinite digest loop is occurring and shuts down. Because new nested arrays/objects were not previously tracked by Angular, it always sees the return value as different from the previous. To fix these "unstable" filters, you must wrap the filter in a memoize function. lodash has a memoize function and the latest version of lodash also includes a chunk function, so we can create this filter very simply using npm modules and compiling the script with browserify or webpack.

Remember: display only! Filter in the controller if you're using inputs!

Install lodash:

npm install lodash-node

Create the filter:

var chunk = require('lodash-node/modern/array/chunk');
var memoize = require('lodash-node/modern/function/memoize');

angular.module('myModule', [])
.filter('chunk', function() {
  return memoize(chunk);
});

And here's a sample with this filter:

<div ng-repeat="row in ['a','b','c','d','e','f'] | chunk:3">
  <div class="column" ng-repeat="item in row">
    {{($parent.$index*row.length)+$index+1}}. {{item}}
  </div>
</div>

Order items vertically

1  4
2  5
3  6

Regarding vertical columns (list top to bottom) rather than horizontal (left to right), the exact implementation depends on the desired semantics. Lists that divide up unevenly can be distributed different ways. Here's one way:

<div ng-repeat="row in columns">
  <div class="column" ng-repeat="item in row">
    {{item}}
  </div>
</div>
var data = ['a','b','c','d','e','f','g'];
$scope.columns = columnize(data, 3);
function columnize(input, cols) {
  var arr = [];
  for(i = 0; i < input.length; i++) {
    var colIdx = i % cols;
    arr[colIdx] = arr[colIdx] || [];
    arr[colIdx].push(input[i]);
  }
  return arr;
}

However, the most direct and just plainly simple way to get columns is to use CSS columns:

.columns {
  columns: 3;
}
<div class="columns">
  <div ng-repeat="item in ['a','b','c','d','e','f','g']">
    {{item}}
  </div>
</div>
m59
  • 43,214
  • 14
  • 119
  • 136
  • Thanks for your help. But Using carousel with ui-chart in angular cannot draw the chart bt carousel works fine. my code is
    And i Initialized my scope variable as milestone JSON data.
    – kuppu May 09 '14 at 18:16
  • @kuppu I can't tell what the problem is just from code in a comment. I recommend posting a new question with details that are specific to your new issue. – m59 May 09 '14 at 21:35
  • @m59 Thank you for this awesome filter. I've been using it successfully prior to Angular 1.3.3 and unfortunately it does not work now with the latest Angular. [I believe it has something to do with this here](https://github.com/angular-translate/angular-translate/issues/694). I see *Unknown provider: pmkrFilterProvider* when using the filter in my `ng-repeat`. Can you provide some insight on how to get this working with Angular 1.3.3? – Ross Nov 19 '14 at 18:31
  • @Ross What's happened is that something in Angular's parsing has changed, and it doesn't allow the `.`, which I use to namespace just about everything :/ Just take off the `pmkr.` namespace. Angular 2.0 is implementing an approach where name collisions are less likely, though I admit they aren't likely anyway and I'm probably the only person to ever really care this much lol. – m59 Nov 19 '14 at 23:54
  • @Kulbir like this? `.row { display: inline-block; width: 33%; }` – m59 Dec 26 '14 at 01:41
  • 1
    @m59 Right now this function displaying data in first row `a b c` second row `d e f`. Can I display `a b ` in first column `c d` in second column and `e f` in third column? Thanks –  Dec 26 '14 at 07:27
  • @m59 `$scope.data = [].concat.apply([], val)` This line awakened interest in me. Why you `apply`ing `array.prototype.contact` in context of empty `array` with `val`. I cannot realize what will be returned. Is it not equal to `[].contact(val)`? – Ifch0o1 Jan 24 '15 at 10:48
  • 1
    @Ifch0o1 You would be correct if that were `[].concat.call([], val)`. You must consider what `apply` does. `val` is an array of arrays, and we want to pass each one of those arrays inside of it as arguments to `concat`. I think you're focusing on the context of `[]`, which isn't the point here. What we want is `[].concat(val[1], val[2], val[3], etc)`, so we need `apply([], val)` – m59 Jan 24 '15 at 17:08
  • @m59 if it is wrong to return new array every time a filter runs, how does angular limitTo works? it does exactly this – bahadir Mar 18 '15 at 11:18
  • 1
    @bahadir I updated the answer to be more clear. Check out what happens if you make a filter that just returns `[]` vs `[[]]` and `[{}]`. The nested array/object makes Angular see a different result on every `filter`, and keeps repeating looking for the result to remain the same (stabilize). – m59 Mar 18 '15 at 14:40
  • thanks for details @m59. but it still doesnt make sense. if i am placing same objects (same memory addresses) to an array [{a = 1},{a=2},{a=3}]. why cant angularjs see that object hasn't changed? – bahadir Mar 19 '15 at 09:38
  • @bahadir It *could*, but it doesn't. It doesn't check for deep equality. Wrapping in a memoize function is a simple fix and makes the function more efficient anyway. – m59 Mar 19 '15 at 14:58
  • @m59 thanks for explanations :) i think you are starting to get tired of me but one last question. i just want to have a deep understanding of angularjs. it doesn't need to check for deep equality all it needs to do is oldArr[x] === newArr[x]. if every member of array is same would it matter is it an object or an integer? – bahadir Mar 19 '15 at 15:41
  • 1
    You're really spamming the comments :) Try it for yourself. `var x = [1,2,3]; var y = [1,2,3]; console.log(x === y);` Deep checking means either stringifying and comparing strings, which is risky because an object may not be stringifiable, or recursively checking each property individually. I think Angular *could* implement that for filters, but I'm sure there's good reason they didn't. Probably because they mainly intended filters for simple modification of a data-set, not a complete overhaul with changes to the structure. – m59 Mar 19 '15 at 15:47
  • I think you did not understand Kulbir's question. If one wants to have the items listed alphabetically down each column not across the rows; how can that be done? Changing the size parameter value does not do that. – user2378769 May 20 '15 at 23:15
  • @user2378769 That's a separate question unrelated to this post. It should be (and probably already is) another post. You could just use/write a function that breaks up an array into sub arrays like `[1,2,3,4,5,6]` into `[[1,4],[2,5],[3,6]]` – m59 May 21 '15 at 01:42
  • Sorry, you are wrong. This is not unrelated. You did not answer the original question. Kuppu, the person that posted the question clarified in a comment that he wanted 1,2,3 in a column NOT 1,2,3 in a row. – user2378769 May 21 '15 at 01:57
  • @user2378769 Bootstrap grids are based on rows of columns (left to right) rather than top to bottom, so the emphasis on bootstrap communicates to me that he is looking for left to right. As my answer originally included demos for the OP and he marked the answer accepted, I have no reason to believe that I did not satisfy his question. Anyway, I updated my answer to include this possibility as well. – m59 May 21 '15 at 03:55
  • What about the following directive for this?https://github.com/jeevasusej/bootstrapRowSplitter – Jeeva J Feb 25 '17 at 13:49
65

This solution is very simple:

JSON:

[{id:"1",name:"testA"},{id:"2",name:"test B"},{id:"3",name:"test C"},{id:"4",name:"test D"},{id:"5",name:"test E"}]

HTML:

<div ng-controller="MyCtrl">
  <table>
    <tr ng-repeat="item in items" ng-switch on="$index % 3">
      <td ng-switch-when="0">
        {{items[$index].id}} {{items[$index].name}}
      </td>
      <td ng-switch-when="0">
        <span ng-show="items[$index+1]">
          {{items[$index+1].id}} {{items[$index+1].name}}
        </span>
      </td>
      <td ng-switch-when="0">
        <span ng-show="items[$index+2]">    
          {{items[$index+2].id}} {{items[$index+2].name}}
        </span>
      </td>
    </tr>
  </table>
</div>

DEMO in FIDDLE

enter image description here

Stéphane GRILLON
  • 11,140
  • 10
  • 85
  • 154
  • 3
    Best answer! And do what is need with native directives ! Congratz! – Renan Franca Jul 28 '15 at 01:20
  • 1
    This solution works, but as far as best practices go, you probably shouldn't be using tables to define layout in your markup :) – Dave Cooper Jun 16 '16 at 14:20
  • 2
    As @DaveCooper mentions, here is an alternative layout without tables: https://plnkr.co/edit/81oj8mHaNyfQpCmRBWO4?p=preview. Consider tables for tabulated data, but otherwise, this is a better layout for mobile devices and variable screen sizes. – Zymotik Jul 20 '16 at 11:41
  • 1
    This is by far the best solution. It takes time to find all the quirks when using a new framework but ng-switch is a godsend – Zoran Aug 01 '16 at 06:12
  • If you are going for div's instead of a table, you could place `ng-switch-when="0"` on an outer div once instead of on all 3 items. – Hans Wouters Mar 28 '17 at 13:05
  • Best solution, I used it for my project using table structure worked really well including pagination and sorting. – SJ Alex Mar 16 '18 at 09:13
  • Still valid today only update on the *ngFor replacing the ng-repeat and the switch case updated according – websplee Feb 12 '22 at 07:50
19

A clean, adaptable solution that does not require data manipulation:

The HTML:

<div class="control-group" class="label"
    ng-repeat="oneExt in configAddr.ext"
    ng-class="{'new-row': startNewRow($index, columnBreak) }">
    {{$index+1}}. 
    <input type="text" name="macAdr{{$index+1}}" 
       id="macAddress{{$index}}" ng-model="oneExt.newValue" />
</div>

The CSS:

.label {
    float: left;
    text-align: left;
}
.new-row {
    clear: left;
}

The JavaScript:

$scope.columnBreak = 3; //Max number of colunms
$scope.startNewRow = function (index, count) {
    return ((index) % count) === 0;
};

This is a simple solution for rendering data into rows and columns dynamically with no need to manipulate the array of data you are trying to display. Plus if you try resizing the browser window you can see the grid dynamically adapts to the size of the screen/div.

(I also added an {{$index}} suffix to your id since ng-repeat will try to create multiple elements with the same id if you do not.)

A similar working example

Cumulo Nimbus
  • 8,785
  • 9
  • 47
  • 68
  • 1
    I believe the OP wanted the markup for Twitter Bootstrap rows/columns, but this may be helpful to someone. However, you need to put the code and explanation in your answer. Link only answers will be removed. – m59 Jan 24 '15 at 17:13
  • 1
    Big +1 for **does not require data manipulation**. This worked perfect for my needs of wanting to separate data in a span using ng-repeat into 2 columns so that my Bootstrap modal wasn't so long! I was surprised how simple this was to implement! `{{z.title}}` That is inside `modal-body'. – Christine268 Jun 03 '15 at 14:52
15

m59's answer is pretty good. The one thing I don't like about it is that it uses divs for what could potentially be data for a table.

So in conjunction with m59's filter (answer somewhere above), here is how to display it in a table.

<table>
    <tr class="" ng-repeat="rows in foos | chunk:2">
        <td ng-repeat="item in rows">{{item}}</td>
    </tr>
</table>
Jarrod
  • 9,349
  • 5
  • 58
  • 73
7

Following is a more simple way:

<table>
    <tr ng-repeat="item in lists" ng-hide="$index%2!==0">
        <td>
            <label>{{ lists[$index].name}}</label>
        </td>
        <td ng-hide="!lists[$index+1]">
            <label>{{ lists[$index+1].name}}</label>
        </td>
    </tr>
</table>

Cumulo Nimbus's answer is useful for me but I want this grid wrapped by a div which can show the scrollbar when the list is too long.

To achieve this I added style="height:200px; overflow:auto" to a div around the table which causes it to show as a single column.

Now works for array length of one.

Anuj Pandey
  • 938
  • 2
  • 11
  • 30
geting
  • 141
  • 1
  • 6
  • when there is only 1 item in array it would not display the first row itself. to fix this change the `ng-hide="$index%2!==0"` – Anuj Pandey Oct 31 '16 at 08:26
4

I have a function and stored it in a service so i can use it all over my app:

Service:

app.service('SplitArrayService', function () {
return {
    SplitArray: function (array, columns) {
        if (array.length <= columns) {
            return [array];
        };

        var rowsNum = Math.ceil(array.length / columns);

        var rowsArray = new Array(rowsNum);

        for (var i = 0; i < rowsNum; i++) {
            var columnsArray = new Array(columns);
            for (j = 0; j < columns; j++) {
                var index = i * columns + j;

                if (index < array.length) {
                    columnsArray[j] = array[index];
                } else {
                    break;
                }
            }
            rowsArray[i] = columnsArray;
        }
        return rowsArray;
    }
}

});

Controller:

$scope.rows   = SplitArrayService.SplitArray($scope.images, 3); //im splitting an array of images into 3 columns

Markup:

 <div class="col-sm-12" ng-repeat="row in imageRows">
     <div class="col-sm-4" ng-repeat="image in row">
         <img class="img-responsive" ng-src="{{image.src}}">
     </div>
 </div>
Chancho
  • 1,930
  • 2
  • 15
  • 20
2

My approach was a mixture of things.

My objective was to have a grid adapting to the screen size. I wanted 3 columns for lg, 2 columns for sm and md, and 1 column for xs.

First, I created the following scope function, using angular $window service:

$scope.findColNumberPerRow = function() {
    var nCols;
    var width = $window.innerWidth;

    if (width < 768) {
        // xs
        nCols = 1;
    }
    else if(width >= 768 && width < 1200) {
         // sm and md
         nCols = 2
    } else if (width >= 1200) {
        // lg
        nCols = 3;
    }
    return nCols;
};

Then, I used the class proposed by @Cumulo Nimbus:

.new-row {
    clear: left;
}

In the div containing the ng-repeat, I added the resizable directive, as explained in this page, so that every time window is resized, angular $window service is updated with the new values.

Ultimately, in the repeated div I have:

ng-repeat="user in users" ng-class="{'new-row': ($index % findColNumberPerRow() === 0) }"

Please, let me know any flaws in this approach.

Hope it can be helpful.

igorauad
  • 648
  • 2
  • 8
  • 11
2

A simple trick with "clearfix" CSS recommended by Bootstrap:

<div class="row">
      <div ng-repeat-start="value in values" class="col-md-4">
        {{value}}
      </div>
      <div ng-repeat-end ng-if="$index % 3 == 0" class="clearfix"></div>
</div>

Many advantages: Efficient, fast, using Boostrap recommendations, avoiding possible $digest issues, and not altering Angular model.

Lastnico
  • 1,473
  • 11
  • 13
1

This example produces a nested repeater where the outer data includes an inner array which I wanted to list in two column. The concept would hold true for three or more columns.

In the inner column I repeat the "row" until the limit is reached. The limit is determined by dividing the length of the array of items by the number of columns desired, in this case by two. The division method sits on the controller and is passed the current array length as a parameter. The JavaScript slice(0, array.length / columnCount) function then applied the limit to the repeater.

The second column repeater is then invoked and repeats slice( array.length / columnCount, array.length) which produces the second half of the array in column two.

<div class="row" ng-repeat="GroupAccess in UsersController.SelectedUser.Access" ng-class="{even: $even, odd: $odd}">
    <div class="col-md-12 col-xs-12" style=" padding-left:15px;">
        <label style="margin-bottom:2px;"><input type="checkbox" ng-model="GroupAccess.isset" />{{GroupAccess.groupname}}</label>
    </div>
    <div class="row" style=" padding-left:15px;">
        <div class="col-md-1 col-xs-0"></div>
        <div class="col-md-3 col-xs-2">
            <div style="line-height:11px; margin-left:2px; margin-bottom:2px;" ng-repeat="Feature in GroupAccess.features.slice(0, state.DivideBy2(GroupAccess.features.length))">
                <span class="GrpFeature">{{Feature.featurename}}</span>
            </div>
        </div>
        <div class="col-md-3 col-xs-2">
            <div style="line-height:11px; margin-left:2px; margin-bottom:2px;" ng-repeat="Feature in GroupAccess.features.slice( state.DivideBy2(GroupAccess.features.length), GroupAccess.features.length )">
                <span class="GrpFeature">{{Feature.featurename}}</span>
            </div>
        </div>
        <div class="col-md-5 col-xs-8">
        </div>
    </div>
</div>


// called to format two columns
state.DivideBy2 = function(nValue) {
    return Math.ceil(nValue /2);
};

Hope this helps to look at the solution in yet another way. (PS this is my first post here! :-))

Harvey Mushman
  • 615
  • 1
  • 11
  • 23
1

I fix without .row

<div class="col col-33 left" ng-repeat="photo in photos">
   Content here...
</div>

and css

.left {
  float: left;
}
selahattinunlu
  • 312
  • 2
  • 8
1
<div class="row">
  <div class="col-md-4" ng-repeat="remainder in [0,1,2]">
    <ul>
      <li ng-repeat="item in items" ng-if="$index % 3 == remainder">{{item}}</li>
    </ul>
  </div>
</div>
mrded
  • 4,674
  • 2
  • 34
  • 36
1

Here's an easy-hacky way of doing it. It's more manual and ends up with messy markup. I do not recommend this, but there are situations where this might be useful.

Here's a fiddle link http://jsfiddle.net/m0nk3y/9wcbpydq/

HTML:

<div ng-controller="myController">
    <div class="row">
        <div class="col-sm-4">
            <div class="well">
                <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3)">
                {{ person.name }}
                </div>
            </div>
        </div>
        <div class="col-sm-4">
            <div class="well">
                <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3):Math.ceil(data.length/3)">
                {{ person.name }}
                </div>
            </div>
        </div>
        <div class="col-sm-4">
            <div class="well">
                <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3):Math.ceil(data.length/3)*2">
                {{ person.name }}
                </div>
            </div>
        </div>
    </div>
</div>

JS:

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

app.controller('myController', function($scope) {

    $scope.Math = Math;
    $scope.data = [
        {"name":"Person A"},
        ...
    ];
});

This setup requires us to use some Math on the markup :/, so you'll need to inject Math by adding this line: $scope.Math = Math;

Gene Parcellano
  • 5,799
  • 5
  • 36
  • 43
1

All of these answers seem massively over engineered.

By far the simplest method would be to set up the input divs in a col-md-4 column bootstrap, then bootstrap will automatically format it into 3 columns due to the 12 column nature of bootstrap:

<div class="col-md-12">
    <div class="control-group" ng-repeat="oneExt in configAddr.ext">
        <div class="col-md-4">
            <input type="text" name="macAdr{{$index}}"
                   id="macAddress" ng-model="oneExt.newValue" value="" />
        </div>
    </div>
</div>
cullimorer
  • 755
  • 1
  • 5
  • 23
0

Basing off of m59's very good answer. I found that model inputs would be blurred if they changed, so you could only change one character at a time. This is a new one for lists of objects for anyone that needs it:

EDIT Updated to handle multiple filters on one page

app.filter('partition', function() {
  var cache = {}; // holds old arrays for difference repeat scopes
  var filter = function(newArr, size, scope) {
    var i,
      oldLength = 0,
      newLength = 0,
      arr = [],
      id = scope.$id,
      currentArr = cache[id];
    if (!newArr) return;

    if (currentArr) {
      for (i = 0; i < currentArr.length; i++) {
        oldLength += currentArr[i].length;
      }
    }
    if (newArr.length == oldLength) {
      return currentArr; // so we keep the old object and prevent rebuild (it blurs inputs)
    } else {
      for (i = 0; i < newArr.length; i += size) {
        arr.push(newArr.slice(i, i + size));
      }
      cache[id] = arr;
      return arr;
    }
  };
  return filter;
}); 

And this would be the usage:

<div ng-repeat="row in items | partition:3:this">
  <span class="span4">
    {{ $index }}
  </span>
</div>
JSous
  • 1,027
  • 7
  • 11
  • As far as I can tell, this should work most of the time but that caching logic doesn't look entirely reliable and passing in the scope is awkward. I really recommend just filtering within the controller when inputs are needed. It's the technically correct approach anyway. – m59 Oct 05 '14 at 20:57
0

I'm new in bootstrap and angularjs, but this could also make Array per 4 items as one group, the result will almost like 3 columns. This trick use bootstrap break line principle.

<div class="row">
 <div class="col-sm-4" data-ng-repeat="item in items">
  <div class="some-special-class">
   {{item.XX}}
  </div>
 </div>
</div>
Nathan
  • 181
  • 1
  • 5
0

Another way is set width:33.33%; float:left to a wrapper div like this:

<div ng-repeat="right in rights" style="width: 33.33%;float: left;">
    <span style="width:60px;display:inline-block;text-align:right">{{$index}}</span>
    <input type="number" style="width:50px;display:inline-block" ">
</div>
Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
geting
  • 141
  • 1
  • 6
0

Lodash has a chunk method built-in now which I personally use: https://lodash.com/docs#chunk

Based on this, controller code might look like the following:

$scope.groupedUsers = _.chunk( $scope.users, 3 )

View code:

<div class="row" ng-repeat="rows in groupedUsers">
  <div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>
sean2078
  • 5,131
  • 6
  • 32
  • 32
0

I found myself in a similar case, wanting to generate display groups of 3 columns each. However, although I was using bootstrap, I was trying to separate these groups into different parent divs. I also wanted to make something generically useful.

I approached it with 2 ng-repeat as below:

<div ng-repeat="items in quotes" ng-if="!($index % 3)">
  <div ng-repeat="quote in quotes" ng-if="$index <= $parent.$index + 2 && $index >= $parent.$index">
                ... some content ...
  </div>
</div>

This makes it very easy to change to a different number of columns, and separated out into several parent divs.

Matt Kindy
  • 358
  • 1
  • 3
  • 12
0

Just in case someone wants an Angular 7 (and higher version) here is an example I used in one of my applications:

HTML:

                   <div class="container-fluid">
                    <div class="row" *ngFor="let reports of chunkData; index as i">
                        <div *ngFor="let report of reports" class="col-4 col-sm-4"
                            style="border-style:solid;background-color: antiquewhite">{{report}}</div>
                    </div>
                </div>

.TS FILE

export class ConfirmationPageComponent implements OnInit {
  chunkData = [];
  reportsArray = ["item 1", "item 2", "item 3", "item 4", "item 5", "item 6"];
  
  constructor() {}

  ngOnInit() {
    this.chunkData = this.chunk(this.reportsArray, 3);
  }

  chunk(arr, size) {
    var newArr = [];
    for (var i = 0; i < arr.length; i += size) {
      newArr.push(arr.slice(i, i + size));
    }
    return newArr;
  }
}

This is an awesome solution for dynamically creating new columns/rows depending on how much items your iterating from the database. THanks!

Gel
  • 2,866
  • 2
  • 18
  • 25
-1

this answers the original question which is how to get 1,2,3 in a column. – asked by kuppu Feb 8 '14 at 13:47

angularjs code:

function GetStaffForFloor(floor) {
    var promiseGet = Directory_Service.getAllStaff(floor);
    promiseGet.then(function (pl) {
        $scope.staffList = chunk(pl.data, 3); //pl.data; //
    },
    function (errorOD) {
        $log.error('Errored while getting staff list.', errorOD);
    });
}
function chunk(array, columns) {
    var numberOfRows = Math.ceil(array.length / columns);

    //puts 1, 2, 3 into column
    var newRow = []; //array is row-based.
    for (var i = 0; i < array.length; i++) {
        var columnData = new Array(columns);
        if (i == numberOfRows) break;
        for (j = 0; j < columns; j++)
        {
            columnData[j] = array[i + numberOfRows * j];
        }
        newRow.push(columnData); 
    }
    return newRow;

    ////this works but 1, 2, 3 is in row
    //var newRow = [];
    //for (var i = 0; i < array.length; i += columns) {
    //    newRow.push(array.slice(i, i + columns)); //push effectively does the pivot. array is row-based.
    //}
    //return newRow;
};

View Code (note: using bootstrap 3):

<div class="staffContainer">
    <div class="row" ng-repeat="staff in staffList">
        <div class="col-md-4" ng-repeat="item in staff">{{item.FullName.length > 0 ? item.FullName + ": Rm " + item.RoomNumber : ""}}</div>
    </div>
</div>
user2378769
  • 309
  • 2
  • 6
-1

This code will help to align the elements with three columns in lg, and md mode, two column in sm mode, and single column is xs mode

<div class="row">
<div ng-repeat="oneExt in configAddr.ext">
    <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
        {$index+1}}. 
        <input type="text" name="macAdr{{$index+1}}" 
       id="macAddress" ng-model="oneExt.newValue" value=""/>
    </div>
</div>

Hari
  • 117
  • 4