【问题标题】:Angular ng-repeat add bootstrap row every 3 or 4 colsAngular ng-repeat 每 3 或 4 列添加引导行
【发布时间】:2015-01-28 11:29:43
【问题描述】:

我正在寻找正确的模式,每 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 模式(没有指令或控制器)来实现这一点吗? docs 介绍了 ng-repeat-start 和 ng-repeat-end 但我不知道如何使用它就是这个用例!我觉得这是我们经常在引导模板中使用的东西! ?谢谢

【问题讨论】:

  • 我认为您应该以适合您的设计的方式对数据进行建模,它可能应该是多维数组或对象,具有行和列的表示,然后您应该遍历行并使用条件类“ ng-class" 指令和行内,然后您应该遍历列。
  • 有趣,当然是一个可行的解决方案,但有一天我想连续显示 4 个产品而不是 3 个,我有,为了修改我的数据结构,我希望它留在“范围”内纯显示功能 ...
  • 我明白了,那么您可能应该像 Ariel 的回答那样分块进行迭代,您也可能会发现这篇文章 stackoverflow.com/questions/18564888/… 很有用。
  • 我认为这正是您要寻找的:stackoverflow.com/a/30426750/1943442

标签: angularjs twitter-bootstrap angularjs-ng-repeat ng-repeat


【解决方案1】:

票数最高的答案虽然有效,但不是我认为的角度方式,也不是使用引导程序自己的类来处理这种情况。正如@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 类来实现其预期目的。

【讨论】:

  • 这是个好主意,但是如果您对使用 flexbox 感兴趣,则必须在行上使用它,而不是在行内的 div 上使用,以允许每个框/div 成为相同的高度。 Clearfix 很棒,但无助于让所有内容保持一致。
  • 这是我的首选答案。非常干净和容易。
  • 也非常适合我的实现! :)
  • 太棒了...这应该被投票为可接受的答案!
  • 这是完美的答案
【解决方案2】:

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

<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

【讨论】:

  • 它实际上帮了我很多!谢谢。
  • 这真的很容易实现!谢谢!
  • 帮了我很多。谢谢!
  • 很好的解决方案,但是它不检查 $index + 1 和 $index +2 是否超过了数组边界。最后两个 div 需要 ng-if="$index+1 &lt; products.length"ng-if="$index+2 &lt; products.length"
  • 我们可以为键值对执行此操作吗?得到下一个钥匙?而不是得到 $index+1
【解决方案3】:

好的,这个解决方案比已经在这里的解决方案简单,并且允许为不同的设备宽度设置不同的列宽。

<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

【讨论】:

  • 在我看来,这是最好的解决方案。
  • 如果是 bootstrap 新手,很容易忽略不需要定义行的事实。这非常有效,是 Duncan 解决方案的一个稍微完整的版本。
  • 这正是我想要的。
  • @phosplait 这比邓肯的有什么优势?
【解决方案4】:

虽然您想要完成的工作可能有用,但我相信您可能会忽略另一个更简单的选项。

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

只需在每个新行的开始之前创建一个空的&lt;div class="clearfix"&gt;&lt;/div&gt;,以允许浮动重置和列返回到它们的正确位置。

这是bootply

【讨论】:

  • 这并不能解决每个 .row 用于引导的负 15px 边距。
  • 这是否与flex 一起使用以使列的高度相同?
【解决方案5】:

感谢您的建议,您让我走上了正确的道路!

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

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

  • 所以如果你想使用@Ariel Array.prototype.chunk 函数,你必须首先将对象转换为数组。

  • 然后使用块函数IN YOUR CONTROLLER,否则如果直接用于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 和上面一样。

优化

悬念的最后一个问题是:如何在不使用块函数扩展 javascript 数组的情况下使其成为 100% AngularJS ... 如果有人有兴趣向我们展示 ng-repeat-start 和 ng-repeat-end 是否是去吧……我很好奇;)

安德鲁的解决方案

感谢@Andrew,我们现在知道每三个(或任何数量)元素添加一个引导 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;
        });

【讨论】:

    【解决方案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>
    

    【讨论】:

      【解决方案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

      【讨论】:

        【解决方案8】:

        我刚刚做了一个解决方案,它只能在模板中工作。 解决办法是

            <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 两次使用数据,一次用于外部循环。 额外的 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 个元素,所以我应该有 3 行,前 2 行有 2 个元素/列,最后一行有 1 列。问题是,我在这里得到 5 行,最后 2 行是空的。想知道如何解决这个问题?谢谢
        • @MaverickAzy 感谢您的尝试。我知道有一个问题,如果这些元素的高度不同,它就不能很好地工作。
        • 元素的高度其实是一样的。问题是,我应该只得到 3 行,但得到 5 行,最后 2 行是空行。你能告诉我 products.length 是 5,那么 5/2+1 = 吗?在第 2 行的课程行中,我不清楚这个逻辑。
        • @MaverickAzy 必须按原样生成那些空行。它会弄乱你的布局吗?
        • 不,它不会弄乱布局。唯一关心的是空行。如果你能帮我解决这个问题,我真的很感激。谢谢
        【解决方案9】:

        关于@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

        【讨论】:

        • 这是否适用于 flex 在行中使列具有相同的高度?
        • 我不确定我是否理解您的问题。这是一个快速向您展示此代码的作用的插件:plnkr.co/edit/4w5wZj?p=preview。换句话说,clearfix 正确对齐了第二行标题:它们都从同一点开始它们仍然没有相同的高度(由于背景颜色,您可以看到)。尝试删除 clearfix 类以查看默认行为。 flexbox 我只用过一两次,但它有很多 css 属性,我相信你能找到你要搜索的东西。
        • bootstrap 提供了an example 如何使同一行中的所有列获得最高列的相同高度。我不得不使用这个。问题是当列数超过 12 列时,它失去了换行的能力,因此您需要手动创建新行。在研究了更多之后,我可以得到一个解决方案并在此处发布作为答案,尽管我不知道它是否是最好的。无论如何,谢谢,你的回答对我有帮助!
        • 第一次看到这个例子,真的很有用!很高兴为您提供帮助。
        【解决方案10】:

        我使用 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>
        

        【讨论】:

          【解决方案11】:

          应用类的最佳方式是使用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";
              }
          }
          

          【讨论】:

            【解决方案12】:

            在这里结合了很多答案和建议,这是我的最终答案,它与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>
            

            【讨论】:

              【解决方案13】:

              @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

              【讨论】:

                【解决方案14】:

                这对我有用,不需要拼接或任何东西:

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

                【讨论】:

                  【解决方案15】:

                  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>
                  

                  【讨论】:

                    【解决方案16】:

                    基于 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">
                        ...
                    

                    这种方法避免了在源模板中复制项目标记(在这种情况下为&lt;span&gt;{{item.name}}&lt;/span&gt;)——对于简单的跨度来说不是一个巨大的胜利,但对于更复杂的 DOM 结构(我有)这有助于保持模板干燥.

                    【讨论】:

                      【解决方案17】:

                      2019 年更新 - Bootstrap 4

                      由于 Bootstrap 3 使用浮点数,它需要 clearfix resets .row 中的每个 n(3 或 4)列 (.col-*) 以防止列的不均匀换行。

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

                      您可以简单地在单个 .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

                      【讨论】:

                        【解决方案18】:

                        我是用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>

                        【讨论】:

                          猜你喜欢
                          • 2014-05-02
                          • 2016-05-24
                          • 1970-01-01
                          • 2015-10-28
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多