Angular ng-repeat每3或4个cols添加一个bootstrap行

问题描述 投票:108回答:19

我正在寻找正确的模式,每3列注入一个bootstrap行类。我需要这个,因为cols没有固定的高度(我不想修复它),所以它打破了我的设计!

这是我的代码:

<div ng-repeat="product in products">
    <div ng-if="$index % 3 == 0" class="row">
        <div class="col-sm-4" >
            ...
        </div>
    </div>
</div>

但它只在每行显示一个产品。我想要的最终结果是:

<div class="row">
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
</div>
<div class="row">
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
</div>

我只能用ng-repeat模式(没有指令或控制器)来实现这个目的吗? docs引入了ng-repeat-start和ng-repeat-end,但我无法弄清楚如何使用它就是这个用例!我觉得这是我们经常在bootstrap模板中使用的东西! ?谢谢

angularjs twitter-bootstrap angularjs-ng-repeat ng-repeat
19个回答
157
投票

最有效的答案,虽然有效,但不是我认为是有角度的方式,也不是使用bootstrap自己的类来处理这种情况。正如@claies所提到的,.clearfix类适用于这些情况。在我看来,最干净的实施如下:

<div class="row">
    <div ng-repeat="product in products">
        <div class="clearfix" ng-if="$index % 3 == 0"></div>
        <div class="col-sm-4">
            <h2>{{product.title}}</h2>
        </div>
    </div>
</div>

这种结构避免了产品数组的混乱索引,允许使用干净的点表示法,并且将clearfix类用于其预期目的。


4
投票

我用ng-class解决了这个问题

<div ng-repeat="item in items">
    <div ng-class="{ 'row': ($index + 1) % 4 == 0 }">
        <div class="col-md-3">
            {{item.name}}
        </div>
    </div>
</div>

2
投票

应用类的最佳方法是使用ng-class.It可用于根据某些条件应用类。

<div ng-repeat="product in products">
   <div ng-class="getRowClass($index)">
       <div class="col-sm-4" >
           <!-- your code -->
       </div>
   </div>

然后在你的控制器中

$scope.getRowClass = function(index){
    if(index%3 == 0){
     return "row";
    }
}

1
投票

在@alpar的解决方案中稍作修改

<div data-ng-app="" data-ng-init="products=['A','B','C','D','E','F', 'G','H','I','J','K','L']" class="container">
    <div ng-repeat="product in products" ng-if="$index % 6 == 0" class="row">
        <div class="col-xs-2" ng-repeat="idx in [0,1,2,3,4,5]">
        {{products[idx+$parent.$index]}} <!-- When this HTML is Big it's useful approach -->
        </div>
    </div>
</div>

jsfiddle


1
投票

在这里结合了许多答案和建议之后,这是我的最终答案,它与flex一起使用,它允许我们创建具有相同高度的列,它还检查最后一个索引,并且您不需要重复内部HTML。它不使用clearfix

<div ng-repeat="prod in productsFiltered=(products | filter:myInputFilter)" ng-if="$index % 3 == 0" class="row row-eq-height">
    <div ng-repeat="i in [0, 1, 2]" ng-init="product = productsFiltered[$parent.$parent.$index + i]"  ng-if="$parent.$index + i < productsFiltered.length" class="col-xs-4">
        <div class="col-xs-12">{{ product.name }}</div>
    </div>
</div>

它将输出如下内容:

<div class="row row-eq-height">
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
</div>
<div class="row row-eq-height">
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
</div>

0
投票

这对我有用,没有拼接或任何要求:

HTML

<div class="row" ng-repeat="row in rows() track by $index">
    <div class="col-md-3" ng-repeat="item in items" ng-if="indexInRange($index,$parent.$index)"></div>
</div>

JavaScript的

var columnsPerRow = 4;
$scope.rows = function() {
  return new Array(columnsPerRow);
};
$scope.indexInRange = function(columnIndex,rowIndex) {
  return columnIndex >= (rowIndex * columnsPerRow) && columnIndex < (rowIndex * columnsPerRow) + columnsPerRow;
};

0
投票

Born Solutions是最好的解决方案,需要一点点调整才能满足需求,我有不同的响应式解决方案并且有所改变

<div ng-repeat="post in posts">
    <div class="vechicle-single col-lg-4 col-md-6 col-sm-12 col-xs-12">
    </div>
    <div class="clearfix visible-lg" ng-if="($index + 1) % 3 == 0"></div>
    <div class="clearfix visible-md" ng-if="($index + 1) % 2 == 0"></div>
    <div class="clearfix visible-sm" ng-if="($index + 1) % 1 == 0"></div>
    <div class="clearfix visible-xs" ng-if="($index + 1) % 1 == 0"></div>
</div>

0
投票

更新2019年 - Bootstrap 4

由于Bootstrap 3使用了浮子,因此在clearfix resets中每n(3或4)列(.col-*)都需要.row,以防止不均匀的包裹。

现在Bootstrap 4使用了flexbox,不再需要将列包装在单独的.row标记中,或者插入额外的div来强制cols包装每n列。

您可以简单地重复单个.row容器中的所有列。

例如,每个可视行中的3列是:

<div class="row">
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     (...repeat for number of items)
</div>

所以对于Bootstrap来说,ng-repeat很简单:

  <div class="row">
      <div class="col-4" ng-repeat="item in items">
          ... {{ item }}
      </div>
  </div>

但是:Kua zxsw指出


0
投票

我只使用bootstrap,你必须非常小心行和列的位置,这是我的例子。


-1
投票

基于Alpar的回答,这是一种将一个项目列表拆分为多个容器(行,列,桶等)的更通用的方法:

<section>
<div class="container">
        <div ng-app="myApp">
        
                <div ng-controller="SubregionController">
                    <div class="row text-center">
                        <div class="col-md-4" ng-repeat="post in posts">
                            <div >
                                <div>{{post.title}}</div>
                            </div>
                        </div>
                    
                    </div>
                </div>        
        </div>
    </div>
</div> 

</section>

对于10个项目的列表,生成:

<div class="row" ng-repeat="row in [0,1,2]">
  <div class="col" ng-repeat="item in $ctrl.items" ng-if="$index % 3 == row">
    <span>{{item.name}}</span>
  </div>
</div> 

容器的数量可以快速编码为控制器功能:

JS(ES6)

<div class="row">
  <div class="col"><span>Item 1</span></div>
  <div class="col"><span>Item 4</span></div>
  <div class="col"><span>Item 7</span></div>
  <div class="col"><span>Item 10</span></div>
</div> 
<div class="row">
  <div class="col"><span>Item 2</span></div>
  <div class="col"><span>Item 5</span></div>
  <div class="col"><span>Item 8</span></div>
</div> 
<div class="row">
  <div class="col"><span>Item 3</span></div>
  <div class="col"><span>Item 6</span></div>
  <div class="col"><span>Item 9</span></div>
</div> 

HTML

$scope.rowList = function(rows) {
  return Array(rows).fill().map((x,i)=>i);
}
$scope.rows = 2;

这种方法避免了在源模板中复制项目标记(在本例中为<div class="row" ng-repeat="row in rowList(rows)"> <div ng-repeat="item in $ctrl.items" ng-if="$index % rows == row"> ... ) - 对于简单的跨度来说不是一个巨大的胜利,但是对于更复杂的DOM结构(我有),这有助于保持模板DRY。


147
投票

我知道它有点晚了但它仍然可以帮助某人。我是这样做的:

<div ng-repeat="product in products" ng-if="$index % 3 == 0" class="row">
    <div class="col-xs-4">{{products[$index]}}</div>
    <div class="col-xs-4" ng-if="products.length > ($index + 1)">{{products[$index + 1]}}</div>
    <div class="col-xs-4" ng-if="products.length > ($index + 2)">{{products[$index + 2]}}</div>
</div>

jsfiddle


24
投票

好的,这个解决方案比这里的解决方案简单得多,并且允许不同的列宽度用于不同的设备宽度。

<div class="row">
    <div ng-repeat="image in images">
        <div class="col-xs-6 col-sm-4 col-md-3 col-lg-2">
            ... your content here ...
        </div>
        <div class="clearfix visible-lg" ng-if="($index + 1) % 6 == 0"></div>
        <div class="clearfix visible-md" ng-if="($index + 1) % 4 == 0"></div>
        <div class="clearfix visible-sm" ng-if="($index + 1) % 3 == 0"></div>
        <div class="clearfix visible-xs" ng-if="($index + 1) % 2 == 0"></div>
    </div>
</div>

请注意,% 6部分应该等于结果列的数量。因此,如果在列元素上有类col-lg-2,则会有6列,因此请使用... % 6

这种技术(不包括ng-if)实际上在这里记录:Bootstrap docs


17
投票

虽然您想要实现的目标可能很有用,但我认为您可能会忽略另一种选择,这种选择要简单得多。

你是对的,当你的列不是固定的高度时,Bootstrap表会很奇怪。但是,有一个bootstrap类创建来解决这个问题并执行responsive resets

只需在每个新行开始之前创建一个空的<div class="clearfix"></div>,以允许浮动重置并使列返回到正确的位置。

这是一个bootply


16
投票

谢谢你的建议,你让我走在正确的道路上!

我们来做一个完整的解释:

  • 默认情况下,AngularJS http get查询返回一个对象
  • 因此,如果您想使用@Ariel Array.prototype.chunk函数,首先要将对象转换为数组。
  • 然后在你的控制器中使用块功能,否则如果直接用于ng-repeat,它将带你到infdig error。最终的控制器看起来: // Initialize products to empty list $scope.products = []; // Load products from config file $resource("/json/shoppinglist.json").get(function (data_object) { // Transform object into array var data_array =[]; for( var i in data_object ) { if (typeof data_object[i] === 'object' && data_object[i].hasOwnProperty("name")){ data_array.push(data_object[i]); } } // Chunk Array and apply scope $scope.products = data_array.chunk(3); });

HTML变成:

<div class="row" ng-repeat="productrow in products">

    <div class="col-sm-4" ng-repeat="product in productrow">

另一方面,我决定直接从我的JSON文件返回一个数组[]而不是一个对象{}。这样,控制器就变成了(请注意具体语法isArray:true):

    // Initialize products to empty list 
    $scope.products = [];

    // Load products from config file
    $resource("/json/shoppinglist.json").query({method:'GET', isArray:true}, function (data_array)
    {
        $scope.products = data_array.chunk(3);
    });

HTML保持与上面相同。

优化

悬念中的最后一个问题是:如何使用100%AngularJS而不扩展具有块功能的javascript数组...如果有人有兴趣向我们展示ng-repeat-start和ng-repeat-end是否可行... 。 我很好奇 ;)

安德鲁的解决方案

感谢@Andrew,我们现在知道每三个(或任何数量)元素添加一个bootstrap clearfix类来纠正不同块高度的显示问题。

所以HTML变成:

<div class="row">

    <div ng-repeat="product in products">

        <div ng-if="$index % 3 == 0" class="clearfix"></div>

        <div class="col-sm-4"> My product descrition with {{product.property}}

并且您的控制器保持安静,具有移除的块功能:

// Initialize products to empty list 
        $scope.products = [];

        // Load products from config file
        $resource("/json/shoppinglist.json").query({method:'GET', isArray:true}, function (data_array)
        {
            //$scope.products = data_array.chunk(3);
            $scope.products = data_array;
        });

7
投票

基于Alpar解决方案,仅使用带有anidated ng-repeat的模板。适用于完整行和部分空行:

<div data-ng-app="" data-ng-init="products='soda','beer','water','milk','wine']" class="container">
    <div ng-repeat="product in products" ng-if="$index % 3 == 0" class="row">
        <div class="col-xs-4" 
            ng-repeat="product in products.slice($index, ($index+3 > products.length ? 
            products.length : $index+3))"> {{product}}</div>
    </div>
</div>

JSFiddle


6
投票

你可以在没有指令的情况下完成,但我不确定这是最好的方法。为此,您必须从要在表中显示的数据创建数组数组,然后使用2 ng-repeat来遍历数组。

创建显示数组使用此函数就像products.chunk(3)

Array.prototype.chunk = function(chunkSize) {
    var array=this;
    return [].concat.apply([],
        array.map(function(elem,i) {
            return i%chunkSize ? [] : [array.slice(i,i+chunkSize)];
        })
    );
}

然后使用2 ng-repeat做类似的事情

<div class="row" ng-repeat="row in products.chunk(3)">
  <div class="col-sm4" ng-repeat="item in row">
    {{item}}
  </div>
</div>

5
投票

我刚刚制作了一个仅在模板中工作的解决方案。解决方案是

    <span ng-repeat="gettingParentIndex in products">
        <div class="row" ng-if="$index<products.length/2+1">    <!-- 2 columns -->
            <span ng-repeat="product in products">
                <div class="col-sm-6" ng-if="$index>=2*$parent.$index && $index <= 2*($parent.$index+1)-1"> <!-- 2 columns -->
                    {{product.foo}}
                </div>
            </span>
        </div>
    </span>

Point正在使用两次数据,一次是外部循环。额外的跨度标签将保留,但这取决于您的权衡方式。

如果它是一个3列布局,它就会像

    <span ng-repeat="gettingParentIndex in products">
        <div class="row" ng-if="$index<products.length/3+1">    <!-- 3 columns -->
            <span ng-repeat="product in products">
                <div class="col-sm-4" ng-if="$index>=3*$parent.$index && $index <= 3*($parent.$index+1)-1"> <!-- 3 columns -->
                    {{product.foo}}
                </div>
            </span>
        </div>
    </span>

老实说我想要

$index<Math.ceil(products.length/3)

虽然没有用。


5
投票

关于@Duncan answer和其他基于clearfix元素的答案的另一个小改进。如果你想让内容可点击,你需要一个z-index> 0或clearfix将重叠内容并处理点击。

这是不起作用的示例(您无法看到光标指针并且单击将不执行任何操作):

<div class="row">
    <div ng-repeat="product in products">
        <div class="clearfix" ng-if="$index % 3 == 0"></div>
        <div class="col-sm-4" style="cursor: pointer" ng-click="doSomething()">
            <h2>{{product.title}}</h2>
        </div>
    </div>
</div>

虽然这是固定的:

<div class="row">
    <div ng-repeat-start="product in products" class="clearfix" ng-if="$index % 3 == 0"></div>
    <div ng-repeat-end class="col-sm-4" style="cursor: pointer; z-index: 1" ng-click="doSomething()">
            <h2>{{product.title}}</h2>
    </div>
</div>

我添加了z-index: 1以使内容提升到clearfix并且我已经使用ng-repeat-startng-repeat-end(可从AngularJS 1.2获得)删除了容器div,因为它使z-index无法正常工作。

希望这可以帮助!

更新

Plunker:http://plnkr.co/edit/4w5wZj

© www.soinside.com 2019 - 2024. All rights reserved.