web-dev-qa-db-ja.com

Angular ng-repeat 3または4列ごとにブートストラップ行を追加

ブートストラップ行クラスを3列ごとに挿入する適切なパターンを探しています。 colsには固定された高さがないため(これを修正したくないため)、これが必要です。

ここに私のコードがあります:

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

ただし、各行に1つの製品のみが表示されます。最終結果として欲しいのは:

<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を紹介しますが、この使用例がどのように使用するかわかりません!これは、ブートストラップテンプレートでよく使用するものだと思います! ?ありがとう

108
hugsbrugs

トップ投票の答えは、効果的ですが、私が角道と考えるものではなく、この状況に対処するためのブートストラップ独自のクラスを使用するものでもありません。 @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クラスを使用します。

154
Duncan

私はそれが少し遅れていることを知っていますが、それはまだ誰かを助けるかもしれません。私はこのようにしました:

<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

147
alpar

さて、この解決策は、farにあるものよりも単純であり、デバイス幅ごとに異なる列幅を使用できます。

<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

24
user3638471

あなたが達成したいことは有用かもしれませんが、私はあなたが見落としているかもしれないと思う別のオプションがあります。

正解です。高さが固定されていない列がある場合、Bootstrapテーブルは奇妙に動作します。ただし、この問題に対処し、 レスポンシブリセット を実行するために作成されたブートストラップクラスがあります。

新しい行の開始前に空の<div class="clearfix"></div>を作成するだけで、フロートをリセットし、列を正しい位置に戻すことができます。

これは bootply です。

17
Claies

あなたの提案をありがとう、あなたは正しい方法で私を得た!

完全な説明に行きましょう:

  • デフォルトでは、AngularJS http getクエリはオブジェクトを返します

  • したがって、@ Ariel Array.prototype.chunk関数を使用する場合は、最初にオブジェクトを配列に変換する必要があります。

  • そして、あなたのコントローラーでチャンク関数を使用するには、そうでなければ直接ng-repeatに使用すると、 infdigエラー 。最終的なコントローラーは次のようになります。

    // 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クラスを3(または任意の数)要素ごとに追加することで、ブロックの高さの違いによる表示の問題を修正できることがわかりました。

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;
        });
16
hugsbrugs

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

7
Juangui Jordán

あなたはディレクティブなしでそれを行うことができますが、私はそれが最良の方法だと確信していません。これを行うには、テーブルに表示するデータから配列の配列を作成し、その後、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>
6
Ariel Henryson

テンプレートでのみ機能するソリューションを作成しました。解決策は

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

ポイントはデータを2回使用していますが、1つは外部ループ用です。余分なスパンタグは残りますが、トレードオフの方法によって異なります。

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
wataru

@ Duncan answer についてのもう1つの小さな改善と、clearfix要素に基づく他の回答。コンテンツをclickableにする場合は、その上に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-startおよびng-repeat-end(AngularJS 1.2から入手可能)を使用してコンテナーdivを削除しました。

お役に立てれば!

更新

プランカー: http://plnkr.co/edit/4w5wZj

5
McGiogen

私は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>
4
Josip

クラスを適用する最良の方法は、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
Rajiv

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

ここで多くの答えと提案を組み合わせた後、これは私の最終的な答えです。これはflexでうまく機能します。これにより、同じ高さの列を作成できます。 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
Alisson

生まれたソリューションはその最高のもので、ニーズに応えるにはほんの少し必要です

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

これは私にとってはうまくいき、スプライシングや何も必要ありませんでした:

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
robbymarston

2019年更新-ブートストラップ4

ブートストラップ3はフロートを使用したため、列の不均等な折り返しを防ぐために、 clearfix resets everyn(3または4)列(.col-*)の.rowが必要でした。

Bootstrap 4がflexboxを使用するようになったため、列を個別の.rowタグでラップしたり、colを毎回強制的にラップするために追加のdivを挿入したりする必要がなくなりましたn列。

単一の.rowコンテナー内の列をすべてall繰り返すだけです。

たとえば、各視覚的行の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
Zim

私はブートストラップのみを使用してそれを行いました。行と列の位置に非常に注意する必要があります。これが私の例です。

<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>
0
Alexis Suárez

この例を試してください

<!DOCTYPE html>
<html>
<head>
        <title></title>

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
        <script type="text/javascript">
                var app = angular.module('myApp', []);

                app.controller('myCtrl', function ($scope,$filter) {
                        $scope.products =[{
                                id:1,
                                name:'aa',
                        },{
                                id:2,
                                name:'bb',
                        },{
                                id:3,
                                name:'cc',
                        },{
                                id:4,
                                name:'dd',
                        },{
                                id:5,
                                name:'ee',
                        }];
                });

        </script>
</head>
<body ng-app="myApp">
        <div ng-controller="myCtrl">
                <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>
        </div>
</body>
</html>
0
Saurabh Agrawal