Angular ng-repeat add bootstrap row every 3 or 4 cols


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>

ただし、各行に表示される製品は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パターンのみ(ディレクティブやコントローラーなし)でこれを実現できますか?ドキュメントは NG-リピートスタートとngのリピートエンドの導入が、私はそれを使用する方法を見つけ出すことはできません。このユースケースです!これは私たちがブートストラップテンプレートでよく使用するものだと思います!?ありがとう


私はあなたのデザインに合う方法でデータをモデル化すべきだと思います、それはおそらく行と列の表現を持つ多次元配列またはオブジェクトである必要があります、そしてあなたは行を反復し、条件付きクラス "ng-class"ディレクティブと内部行を使うべきです次に、列を反復処理する必要があります。
antanas_sepikas 2014年

面白くて確かに機能するソリューションですが、3つの製品ではなく4つの製品を1行ずつ表示したい場合、データ構造を変更するために、純粋な表示機能の「スコープ」にとどまる方がいいと思います...
hugsbrugs

なるほど、おそらくアリエルの回答のようにチャンクで反復処理する必要があります。また、この投稿stackoverflow.com/questions/18564888/…も役立つでしょう。
antanas_sepikas 2014年

これはまさにあなたが探しているものだと思います:stackoverflow.com/a/30426750/1943442
user1943442

回答:


164

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

この構造により、products配列の乱雑なインデックス付けが回避され、クリーンなドット表記が可能になり、目的の目的でclearfixクラスが使用されます。


6
これは良い考えですが、フレックスボックスの使用に関心がある場合は、各ボックス/ divの高さを同じにするために、行内のdivではなく、行でこれを使用する必要があります。Clearfixは素晴らしいですが、すべてを揃えるのに役立ちません。
コード化されたコンテナ

3
これが私の好ましい答えです。とても清潔で簡単。
Hinrich、2015年

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

それは本当に簡単に実装できます!ありがとう!
Manas Bajaj

私を大いに助けてくれました。ありがとう!
Ahmad Ajmi 2015年

17
優れたソリューションですが、$ index + 1と$ index +2が配列の境界を超えているかどうかはチェックしません。最後の2つのdivにはrequire ng-if="$index+1 < products.length"およびng-if="$index+2 < products.length"
Mustafa Ozturk '30 / 07/30

これをキーと値のペアに対して実行できますか?次のキーを取得しますか?$ 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パーツは、結果の列の数に等しいと想定されていることに注意してください。したがって、列要素にクラスcol-lg-2がある場合、6つの列があるので、... % 6

この手法(を除くng-if)は、実際にはここに記載されています。Bootstrapdocs


1
私の意見では、これが最良の解決策です。
user216661

ブートストラップを初めて使用する場合、行を定義する必要がないという事実を見落としがちです。これは完全に機能し、ダンカンのソリューションのもう少し完全なバージョンです。
phosplait 2016

これはまさに私が探していたものです。
Hinrich 2017

@phosplaitこれはダンカンの利点とは何ですか?
Jeppe

17

あなたが達成したいことは役に立つかもしれませんが、あなたが見落としているかもしれない別のオプションがあり、それはもっと簡単です。

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

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

こちらがブーツプライです。


これは、各.rowがブートストラップ用に持っているマイナス15pxのマージンを解決しません。
Logus

これはflex、列を同じ高さにするために機能しますか?
Alisson

16

あなたの提案をありがとう、あなたは私を正しい道に導きました!

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

  • デフォルトでは、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のおかげで、3つ(または任意の数)の要素ごとにブートストラップの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>

ポイントはデータを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)

うまくいきませんでしたが。


このソリューションを試して、各行に2つの要素を実装しました。たとえば、リストに5つの要素があるため、出力が3行で、最初の2行に2つの要素/列があり、最後の行に1つの列があります。問題は、最後の2行が空の状態で5行取得していることです。これを修正する方法を知りたいですか?ありがとう
Maverick Riz

@MaverickAzy試していただきありがとうございます。これらの要素の高さが異なるとうまく機能しないという問題があることを知っています。
wataru

要素の高さは実際には同じです。問題は、3行しか取得できないはずですが、最後の2行が空の5行が取得されることです。products.lengthが5で、5/2 + 1 =かどうか教えてください。この論理は、クラス行の2行目ではわかりません。
マーベリックリズ2015

@MaverickAzyそれらの空の行はそのまま生成する必要があります。それはあなたのレイアウトを台無しにしますか?
wataru

いいえ、レイアウトが乱れることはありません。空の行に関する問題のみです。これで私を助けることができれば本当に感謝しています。ありがとう
マーベリックリズ

5

@Duncanの回答についてのもう1つの小さな改善と、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: 1clearfixよりもコンテンツを上げるように追加し、代わりにng-repeat-startを使用してコンテナーdivを削除しました。ng-repeat-end(AngularJS 1.2から入手可能)。これにより、Zインデックスが機能しなくなりました。

お役に立てれば!

更新

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


これは行内で機能しflex、列を同じ高さにしますか?
Alisson

私はあなたの質問を理解しているのかわかりません。これは、このコードが何をするかを示すための高速プランカーです:plnkr.co/edit/4w5wZj?p=preview。言葉では、clearfixは正しくタイトルの2行目を合わせる:それらはすべて同じ地点から開始するが、(あなたは、背景色のおかげで見ることができるように)彼らはまだ同じ高さを持っていません。clearfixクラスを削除して、デフォルトの動作を確認してください。flexboxを 1、2回だけ使用しましたが、cssプロパティがたくさんあり、あなたが探しているものを見つけることができると確信しています。
McGiogen

ブートストラップはすべての列を同じ行に作成して、最も高い列の高さを同じにする方法の例を提供ます。これを使わなければなりませんでした。問題は、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構造(私が持っていた)の場合、これはテンプレートをDRYに保つのに役立ちます。


0

アップデート2019-ブートストラップ4

Bootstrap 3は浮動小数点を使用していたため、列の不均一な折り返しを防ぐために、n(3または4)列ごとにclearfixをリセットする必要があります()。.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

私はブーストラップを使ってそれをしました、あなたは行と列の位置に非常に注意しなければなりません、これが私の例です。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.