角ng-repeat每3或4列添加引导行


111

我正在寻找正确的模式以每3列注入一个引导行类。我需要这个是因为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模式(不使用指令或控制器)来实现吗?该文档介绍了ng-repeat-start和ng-repeat-end,但是我无法弄清楚在此用例中如何使用它!我觉得这是我们在引导模板中经常使用的东西!?谢谢


我认为您应该以适合您的设计的方式对数据建模,它可能应该是多维数组或对象,并具有行和列的表示形式,然后您应该遍历行并使用条件类“ ng-class”指令和行内然后,您应该遍历列。
antanas_sepikas 2014年

有趣的并且肯定是可行的解决方案,但是那天我要连续显示4个产品而不是3个,我不得不修改我的数据结构,我希望它停留在纯显示功能的“范围”内……
hugsbrugs

我明白了,那么您应该像Ariel回答中那样以块为单位进行迭代,也可能会发现这篇文章stackoverflow.com/questions/18564888/…有用。
antanas_sepikas 2014年

我认为这正是您要寻找的东西:stackoverflow.com/a/30426750/1943442
user1943442 2015年

Answers:


164

投票最多的答案虽然有效,但不是我认为是棱角分明的方法,也不是使用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>

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


6
这是一个好主意,但是,如果您对使用flexbox感兴趣,则必须在行上而不是在行内的div上使用它,以使每个box / div的高度相同。Clearfix很棒,但是并不能使所有内容保持一致。
编码容器

3
这是我的首选答案。非常干净和容易。
辛里奇

1
同样适用于我的实现!:)
Will Strohl

1
太好了...应该将其投票为可接受的答案!
Velu

3
这是完美的答案
Deepu

148

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

<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


3
它实际上对我有很大帮助!谢谢。
SupimpaAllTheWay 2015年

这真的很容易实现!谢谢!
Manas Bajaj 2015年

对我有很大帮助。谢谢!
艾哈迈德·阿吉米

17
很棒的解决方案,但是它不会检查$ index + 1和$ index +2是否超出数组边界。最后两个div要求ng-if="$index+1 < products.length"ng-if="$index+2 < products.length"
Mustafa Ozturk

我们可以对键值对执行此操作吗?获取下一个键?而不是获得$ index + 1
bpbhat77

25

好了,该解决方案远远比那些简单的已经在这里,并允许不同的设备宽度不同的列宽。

<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部分应该等于结果列数。因此,如果在column元素上有类col-lg-2,则将有6列,因此请使用... % 6

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


1
我认为这是最好的解决方案。
user216661 '02

如果不熟悉引导程序,则很容易忽略不需要定义行的事实。这完美地工作了,是Duncan解决方案的稍完整版本。
phosplait

这正是我想要的。
Hinrich

@phosplait与Duncan相比,这有什么优势?
杰普

17

尽管您想要完成的工作可能会有用,但是我认为您可能会忽略另一个选择,它要简单得多。

没错,当列的高度不固定时,Bootstrap表的行为会很奇怪。但是,创建了一个引导类来解决此问题并执行响应式重置

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

这是靴子


这不能解决每个.row引导所具有的负15px的空白。
Logus '16

flex可以使列具有相同的高度吗?
阿里森

16

感谢您的建议,您使我步入正轨!

让我们进行完整的解释:

  • 默认情况下,AngularJS http get查询返回一个对象

  • 因此,如果要使用@Ariel Array.prototype.chunk函数,则必须首先将对象转换为数组。

  • 然后在您的控制器中使用块函数,否则,如果直接将其用于ng-repeat中,则会导致输入错误。最终的控制器看起来是:

    // 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保持与上面相同。

优化

悬念中的最后一个问题是:如何在不使用块函数扩展JavaScript数组的情况下使其成为100%AngularJS ...如果有人有兴趣向我们展示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}}

并且您的控制器保持了相当软的状态,并删除了chunck函数:

// 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

您可以在没有指令的情况下执行此操作,但我不确定这是最佳方法。为此,您必须根据要在表中显示的数据创建一个数组数组,然后使用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>

7

基于Alpar解决方案,仅使用带有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


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>

点是两次使用数据,一个是用于外部循环。会保留额外的跨度标签,但这取决于您如何权衡。

如果它是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)

虽然没有用。


我尝试使用此解决方案在每行中实现2个元素。例如,我在一个列表中有5个元素,因此输出i应该是3行,前2行有2个元素/列,最后一行有1列。问题是,我在这里得到5行,最后2行为空。想知道如何解决这个问题?谢谢
Maverick Riz 2015年

@MaverickAzy感谢您的尝试。我知道有一个问题,如果这些元素的高度不同,那么效果就不好。
wataru 2015年

元素的高度实际上是相同的。问题是,我应该只得到3行,但是得到5行,最后2个空行。您能告诉我products.length是否为5,那么5/2 + 1 =吗?对于班级行的第二行,这种逻辑对我来说还不清楚。
Maverick Riz 2015年

@MaverickAzy这些空行必须按原样生成。它会打乱您的布局吗?
wataru 2015年

不,它不会弄乱布局。唯一关心的是空行。真的很感激,如果您能帮助我的话。谢谢
Maverick Riz

5

关于@Duncan答案和基于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


这是否可以flex在行中使列具有相同的高度?
Alisson

我不确定我是否理解您的问题。这是一个向您展示此代码功能的快速插件:plnkr.co/edit/4w5wZj?p=preview。换句话说,clearfix正确地对齐了标题的第二行:它们都从同一点开始,但是它们仍然没有相同的高度(由于背景色,您可以看到)。尝试删除clearfix类以查看默认行为。我只使用过flexbox一两次,但是它具有很多CSS属性,并且我确定您可以找到要搜索的内容。
McGiogen '16

bootstrap提供了一个示例,说明如何使同一行中的所有列都具有与最高列相同的高度。我不得不用这个。问题是当多于12列时,它失去了换行的能力,因此您需要手动创建新行。经过更多研究后,我可以找到一个解决方案,并在此处作为答案发布,尽管我不知道这是否是最好的解决方案。无论如何,谢谢您的回答对我有所帮助!
Alisson

这是我第一次看到该示例,它真的很有用!很高兴为您提供帮助。
McGiogen

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,它可以根据某些条件来应用类。

<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";
    }
}

2

在这里组合了许多答案和建议之后,这是我的最终答案,它与搭配使用效果很好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>

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


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

在Alpar的答案的基础上,这是将项目列表拆分为多个容器(行,列,存储桶等)的更通用的方法:

<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> 

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

<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> 

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

JS(ES6)

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

的HTML

<div class="row" ng-repeat="row in rowList(rows)">
  <div ng-repeat="item in $ctrl.items" ng-if="$index % rows == row">
    ...

这种方法避免了<span>{{item.name}}</span>在源模板中重复项目标记(在这种情况下)-对于简单的跨度而言并不是一个巨大的胜利,但是对于更复杂的DOM结构(我拥有),这有助于使模板保持干燥。


0

更新2019-Bootstrap 4

由于自举3个中使用浮筒,它需要clearfix重置Ñ(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>

演示:https//www.codeply.com/go/Z3IjLRsJXX


0

我仅使用boostrap做到了这一点,您必须非常注意行和列的位置,这是我的示例。

<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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.