angular.js ng-repeat用于创建网格

时间:2013-11-22 05:15:14

标签: javascript angularjs twitter-bootstrap

我正在尝试使用bootstrap 3和angularjs创建一个网格。

我正在尝试创建的网格是这样,使用ng-repeat重复。

<div class="row">
 <div class="col-md-4">item</div>
 <div class="col-md-4">item</div>
 <div class="col-md-4">item</div>
</div>

我尝试将ng-if($index % 3 == 0)一起使用来添加行,但这似乎并不正常。任何建议都会很棒!

谢谢!

编辑:这是我最终使用的代码:

<div ng-repeat="item in items">
  <div ng-class="row|($index % 3 == 0)">
    <ng-include class="col-sm-4" src="'views/items/item'"></ng-include> 
  </div>
</div>

11 个答案:

答案 0 :(得分:71)

接受的答案是明显的解决方案,但是表示逻辑应保持在视图中而不是控制器或模型中。此外,我无法使OP的解决方案起作用。

当您有一个项目的平面列表(数组)时,有两种方法可以创建网格系统。 假设我们的项目列表是一个字母:

Plunker here

$scope.alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
                   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

方法1:

这是一个纯粹的角度解决方案。

<div class="row" ng-repeat="letter in alphabet track by $index" ng-if="$index % 4 == 0">
  <div class="col-xs-3 letter-box" 
       ng-repeat="i in [$index, $index + 1, $index + 2, $index + 3]" 
       ng-if="alphabet[i] != null">
    <div>Letter {{i + 1}} is: <b> {{alphabet[i]}}</b></div>
  </div>
</div>

外部循环在每4次迭代后执行并创建一行。对于外循环的每次运行,内循环迭代4次并创建列。由于内部循环运行4次,无论我们是否在数组中都有元素,ng-if确保如果数组在内部循环完成之前结束,则不会创建无关的cols。

方法2:

这是一个更简单的解决方案,但需要angular-filter库。

<div class="row" ng-repeat="letters in alphabet | chunkBy:4">
  <div class="col-xs-3 letter-box" ng-repeat="letter in letters" >
    <div>Letter {{$index + 1}} is: <b> {{letter}}</b></div>
  </div>
</div>

外部循环创建4个字母的组,对应于我们的“行”

[['A', 'B', 'C', 'D'], ['E', 'F', 'G', 'H'], ... ]

内部循环遍历组并创建列。

注意:方法2可能需要为外循环的每次迭代评估过滤器,因此方法2可能无法很好地扩展到大型数据集。

答案 1 :(得分:21)

这是一个陈旧的答案!

当我写这篇文章时,我对Angular还有点新意。 Shivam下面有一个更好的答案我建议你改用。它使表示逻辑远离控制器,这是一件非常好的事情。

原始回答

您始终可以将要重复的列表拆分为控制器中的列表列表(每个列表中包含三个项目)。所以你列出的是:

$scope.split_items = [['item1', 'item2', 'item3'], ['item4', 'item5', 'item6']];

然后重复:

<div ng-repeat="items in split_items" class="row">
    <div ng-repeat="item in items" class="col-md-4">
        item
    </div>
</div>

不确定是否有更好的方法。我也试过玩ng-if和ng-switch,但我永远无法让它工作。

答案 2 :(得分:9)

您可以简单地将数组块化为控制器内部N的子阵列。示例代码:

var array = ['A','B','C','D','E','F','G','H'];

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

$scope.array = chunk(array, 2);

现在在* .html文件中您只需ng-repeat通过array

<div class="row" ng-repeat="chunk in array">
    <div class="col-md-6" ng-repeat="item in chunk">
         {{item}}
    </div>
</div>

对我来说锻炼:) 祝你好运!

答案 3 :(得分:3)

有人可能会说下面的解决方案不遵循具有row div的网格规则,但另一种解决方案是删除row类(或在ng-repeat之外使用它})并使用clearfix类代替:

<div class="col-md-12">
  <div ng-repeat="item in items">
    <div ng-class="{'clearfix': $index%3 === 0}"></div>
    <div class="col-md-4">{{item}}</div>
  </div>
</div>

据我所知,这看起来与row类几乎相同,但请评论可能存在的缺陷(除了我上面提到的那个)。

答案 4 :(得分:3)

使用 ng-repeat-start ng-repeat-end

<div class="row">
    <div ng-repeat-start="item in items track by $index" class="col-sm-4">
      {{item}}
    </div>
    <div ng-repeat-end ng-if="($index+1) % 3 == 0" class="clearfix"></div>
</div>

使用 .visible - *

轻松适应不同的媒体查询
<div class="row">
    <div ng-repeat-start="item in items track by $index" class="col-lg-2 col-md-4 col-sm-6">
      {{item}}
    </div>
    <div ng-repeat-end>
        <div class="clearfix visible-lg-block" ng-if="($index+1) % 6 == 0"></div>
        <div class="clearfix visible-md-block" ng-if="($index+1) % 3 == 0"></div>
        <div class="clearfix visible-sm-block" ng-if="($index+1) % 2 == 0"></div>
    </div>
</div> 

我发现在主重复块之外有行管理逻辑,简洁明了。关注点分离: - )

答案 5 :(得分:2)

有点迟到但我使用了这个,我相信它对某些情况更好。您可以使用Angular Filter包及其ChunkBy过滤器。虽然这个程序包对于这个单一任务来说将是一个繁重的工具,但它还有其他有用的过滤器用于不同的任务。我使用的代码是这样的:

<div class="row mar-t2" ng-repeat="items in posts | chunkBy:3">
    <div class="col-md-4" ng-repeat="post in items">
        <img ng-src="{{post.featured_url}}" class="img-responsive" />
        <a ng-click="modalPop(post.id)"><h1 class="s04-bas2">{{post.title.rendered}}</h1></a>
        <div class="s04-spotbox2" ng-bind-html="post.excerpt.rendered"></div>
    </div>
</div>

答案 6 :(得分:0)

我使用ngInit采用了稍微不同的方法。我不确定这是否是适当的解决方案,因为ngInit文档说明了

  

ngInit的唯一合适用途是用于别名ngRepeat的特殊属性,如下面的演示所示。除了这种情况,您应该使用控制器而不是ngInit来初始化作用域上的值。

我不确定这是否属于这种情况,但我想将此功能从控制器中移开,以便让模板设计人员更容易自由地按行分组。我仍然没有对这个绑定进行测试,但看到我按$ index跟踪我并不认为这应该是一个问题。

很想听到反馈。

我创建了一个名为&#34; splitrow&#34;的过滤器。这需要一个参数(每行中有多少项)

.filter('splitrow', function(){
    return function (input, count){
        var out = [];
            if(typeof input === "object"){
                for (var i=0, j=input.length; i < j; i+=count) {
                    out.push(input.slice(i, i+count));
                }
            }
        return out;
    }
});

在视图模板中,我按如下方式组织了引导行:

<div ng-init="rows = (items|splitrow:3)">
    <div ng-repeat='row in rows' class="row">
        <div ng-repeat="item in row track by $index" class="col-md-4">
            {{item.property}}
        </div>
    </div>
</div>

我编辑了@ Shivam的Plunker来使用这种方法。它不需要外部库。

Plunker

答案 7 :(得分:0)

我的解决方案与@CodeExpress非常相似。我创建了一个batch过滤器,用于对数组中的项进行分组(名称是从Twig's counterpart filter借来的)。 为简单起见,我不处理关联数组。

angular.module('myapp.filters', [])
    .filter('batch', function() {
        var cacheInputs = [];
        var cacheResults = [];

        return function(input, size) {
            var index = cacheInputs.indexOf(input);

            if (index !== -1) {
                return cacheResults[index];
            }

            var result = [];

            for (i = 0; i < input.length; i += size) {
                result.push(input.slice(i, i + size));
            }

            cacheInputs.push(input);
            cacheResults.push(result);

            return result;
        }
    })
;

可以这样使用:

<div ng-repeat="itemsRow in items|batch:3">
    <div class="row">
        <div ng-repeat="item in itemsRow">
            <div class="col-md-4">
                ...
            </div>
        </div>
    </div>
</div>

缓存过滤器结果以避免10 $digest() iterations reached. Aborting!错误。

答案 8 :(得分:0)

@ CodeExpress的纯角度解决方案的Angular2版本。

alphabet: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
                   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

<div *ngIf='alphabet && alphabet.length'>
    <div *ngFor='#letter of alphabet; #i = index' >
        <div class="row" *ngIf='i % 4 == 0'>
            <div class="col-md-3" *ngFor='#n of [i,i+1,i+2,i+3]'>
                {{alphabet[n]}}
            </div>
        </div>
    </div>
</div>

答案 9 :(得分:0)

这应该有效

<div ng-repeat="item in items">
    <div ng-class="{row : ($index % 3 == 0)}">
        ... 
    </div>
</div>

答案 10 :(得分:0)

更新Angular9:

<div class="container-fluid" *ngFor="let item of alphabet; let index = index">
  <div class="row" *ngIf="index % 4 == 0">
    <div *ngFor="let i of [index, index+1, index+2, index+3]">
      <div class="col-xs-3">{{alphabet[i]}}</div>
    </div>
  </div>
</div>