Angular ng-repeat tambahkan baris bootstrap setiap 3 atau 4 kolom


111

Saya mencari pola yang tepat untuk memasukkan kelas baris bootstrap setiap 3 kolom. Saya memerlukan ini karena cols tidak memiliki tinggi tetap (dan saya tidak ingin memperbaikinya), jadi desain saya rusak!

Ini kode saya:

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

Tapi itu hanya menampilkan satu produk di setiap baris. Yang saya inginkan sebagai hasil akhir adalah:

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

Bisakah saya mencapai ini hanya dengan pola ng-repeat (tanpa direktif atau controller)? The docs memperkenalkan ng-repeat-start dan ng-repeat-end tapi saya tidak tahu bagaimana menggunakannya adalah kasus penggunaan ini! Saya merasa ini adalah sesuatu yang sering kita gunakan dalam template bootstrap! ? Terima kasih


Saya pikir Anda harus memodelkan data Anda dengan cara yang sesuai dengan desain Anda, itu mungkin harus berupa array atau objek multidimensi, dengan representasi baris dan kolom, maka Anda harus mengulang baris dan menggunakan kelas bersyarat "ng-class" direktif dan baris dalam Anda kemudian harus mengulangi kolom.
antanas_sepikas

Menarik dan tentu saja solusi yang berfungsi tetapi pada hari saya ingin menampilkan 4 produk berturut-turut, bukan 3, saya harus, untuk mengubah struktur data saya, saya lebih suka ini tetap dalam "ruang lingkup" fungsi tampilan murni ...
hugsbrugs

Begitu, maka Anda mungkin harus mengulang dalam potongan seperti dalam jawaban Ariel, Anda juga dapat menemukan posting ini stackoverflow.com/questions/18564888/… berguna.
antanas_sepikas

Saya pikir inilah yang Anda cari: stackoverflow.com/a/30426750/1943442
user1943442

Jawaban:


164

Jawaban pilihan teratas, meski efektif, bukanlah apa yang saya anggap sebagai cara bersudut, juga tidak menggunakan kelas bootstrap sendiri yang dimaksudkan untuk menangani situasi ini. Seperti yang disebutkan @claies, .clearfixkelas tersebut dimaksudkan untuk situasi seperti ini. Menurut saya, implementasi terbersih adalah sebagai berikut:

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

Struktur ini menghindari pengindeksan yang berantakan pada larik produk, memungkinkan notasi titik yang bersih, dan menggunakan kelas clearfix untuk tujuan yang dimaksudkan.


6
Ini adalah ide yang bagus, namun jika Anda tertarik untuk menggunakan flexbox, Anda harus menggunakan ini pada baris dan bukan pada div di dalam baris agar setiap kotak / div memiliki ketinggian yang sama. Clearfix bagus tetapi tidak membantu menjaga semuanya tetap berbaris.
Wadah

3
Ini adalah jawaban pilihan saya. Sangat bersih dan mudah.
Hinrich

1
Berfungsi bagus untuk implementasi saya juga! :)
Will Strohl

1
Hebat ... Ini harus dipilih sebagai jawaban yang diterima!
Velu

3
Ini adalah jawaban yang sempurna
Deepu

148

Saya tahu ini agak terlambat tetapi mungkin masih membantu seseorang. Saya melakukannya seperti ini:

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


3
itu benar-benar banyak membantu saya !! Terima kasih.
SupimpaAllTheWay

Itu sangat mudah diterapkan! Terima kasih!
Manas Bajaj

Banyak membantu saya. Terima kasih!
Ahmad Ajmi

17
Solusi hebat, namun tidak memeriksa apakah $ index + 1 dan $ index +2 melewati batas array. Dua div terakhir membutuhkan ng-if="$index+1 < products.length"danng-if="$index+2 < products.length"
Mustafa Ozturk

Bisakah kita melakukan ini untuk key, value pair. mendapatkan kunci berikutnya? Alih-alih mendapatkan $ indeks + 1
bpbhat77

25

Oke, solusi ini jauh lebih sederhana daripada yang sudah ada di sini, dan memungkinkan lebar kolom yang berbeda untuk lebar perangkat yang berbeda.

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

Perhatikan bahwa % 6bagian tersebut seharusnya sama dengan jumlah kolom yang dihasilkan. Jadi jika pada elemen kolom Anda memiliki kelas col-lg-2akan ada 6 kolom, jadi gunakan... % 6 .

Teknik ini (tidak termasuk ng-if) sebenarnya didokumentasikan di sini: Dokumentasi bootstrap


1
Menurut saya, ini adalah solusi terbaik.
pengguna216661

Jika baru mengenal bootstrap, mudah untuk mengabaikan fakta bahwa mendefinisikan baris tidak diperlukan. Ini bekerja dengan sempurna dan merupakan versi solusi Duncan yang sedikit lebih lengkap.
phosplait

Inilah yang saya cari.
Hinrich

@phosplait Apa keuntungan dari ini dibandingkan Duncan?
Jeppe

17

Meskipun apa yang ingin Anda capai mungkin berguna, ada opsi lain yang saya yakin Anda abaikan yang jauh lebih sederhana.

Anda benar, tabel Bootstrap bertindak aneh ketika Anda memiliki kolom yang tingginya tidak tetap. Namun, ada kelas bootstrap yang dibuat untuk mengatasi masalah ini dan melakukan penyetelan ulang responsif .

cukup buat yang kosong <div class="clearfix"></div> sebelum awal setiap baris baru untuk memungkinkan pelampung diatur ulang dan kolom untuk kembali ke posisi yang benar.

ini adalah bootply .


Ini tidak menyelesaikan margin negatif 15px yang dimiliki setiap .row untuk bootstrap.
Logus

Apakah ini berfungsi dengan flexmembuat kolom memiliki ketinggian yang sama?
Alisson

16

Terima kasih atas saran Anda, Anda membuat saya di jalan yang benar!

Mari kita lihat penjelasan lengkapnya:

  • Secara default AngularJS http mendapatkan query mengembalikan sebuah objek

  • Jadi jika Anda ingin menggunakan fungsi @Ariel Array.prototype.chunk Anda harus terlebih dahulu mengubah objek menjadi sebuah array.

  • Dan kemudian untuk menggunakan fungsi chunk DI CONTROLLER ANDA sebaliknya jika digunakan langsung ke ng-repeat, itu akan membawa Anda ke kesalahan infdig . Pengontrol terakhir terlihat:

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

Dan HTML menjadi:

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

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

Di sisi lain, saya memutuskan untuk langsung mengembalikan larik [] alih-alih objek {} dari file JSON saya. Dengan cara ini, pengontrol menjadi (harap perhatikan sintaks spesifik 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 tetap sama seperti di atas.

OPTIMASI

Pertanyaan terakhir dalam ketegangan adalah: bagaimana membuatnya 100% AngularJS tanpa memperluas array javascript dengan fungsi chunk ... jika beberapa orang tertarik untuk menunjukkan kepada kita jika ng-repeat-start dan ng-repeat-end adalah cara yang harus dilakukan .. . Saya penasaran ;)

SOLUSI ANDREW

Berkat @Andrew, kami sekarang tahu menambahkan kelas bootstrap clearfix setiap tiga (atau nomor berapa pun) elemen memperbaiki masalah tampilan dari ketinggian blok differents.

Jadi HTML menjadi:

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

Dan pengontrol Anda tetap cukup lunak dengan fungsi chunck yang dihapus :

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

Anda dapat melakukannya tanpa arahan tetapi saya tidak yakin itu cara terbaik. Untuk melakukan ini, Anda harus membuat array dari data yang ingin Anda tampilkan di tabel, dan setelah itu gunakan 2 ng-repeat untuk melakukan iterasi melalui array.

untuk membuat array untuk tampilan, gunakan fungsi ini seperti 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)];
        })
    );
}

dan kemudian lakukan hal seperti itu menggunakan 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

Berdasarkan solusi Alpar, hanya menggunakan template dengan anidated ng-repeat. Bekerja dengan baris kosong penuh dan sebagian:

<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

Saya baru saja membuat solusinya hanya berfungsi di template. Solusinya adalah

    <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 menggunakan data dua kali, satu untuk loop luar. Tag span ekstra akan tetap ada, tetapi itu tergantung pada bagaimana Anda melakukan trade off.

Jika itu adalah tata letak 3 kolom, itu akan menjadi seperti

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

Jujur saya ingin

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

Meskipun tidak berhasil.


Saya mencoba solusi ini untuk menerapkan 2 elemen di setiap baris. Misalnya, saya memiliki 5 elemen dalam daftar, jadi output yang harus saya miliki adalah 3 baris dengan 2 elemen / kolom di 2 baris pertama dan 1 kolom di baris terakhir. Masalahnya adalah, saya mendapatkan 5 baris di sini dengan 2 baris terakhir kosong. Ingin tahu bagaimana cara memperbaikinya? Terima kasih
Maverick Riz

@MaverickAzy terima kasih sudah mencoba. Saya tahu ada masalah bahwa jika ketinggian elemen itu berbeda, itu tidak berfungsi dengan baik.
wataru

Ketinggian elemen sebenarnya sama. Masalahnya adalah, saya seharusnya hanya mendapatkan 3 baris tetapi mendapatkan 5 baris dengan 2 baris kosong terakhir. Bisakah Anda memberi tahu saya jika products.length adalah 5, lalu 5/2 + 1 =? Logika ini tidak jelas bagi saya di baris no.2 untuk baris kelas.
Maverick Riz

@MaverickAzy baris kosong itu harus dibuat apa adanya. Apakah itu mengacaukan tata letak Anda?
wataru

tidak, itu tidak mengacaukan tata letak. Satu-satunya perhatian adalah tentang baris kosong. Sangat menghargai jika Anda dapat membantu saya dengan ini. Terima kasih
Maverick Riz

5

Sedikit perbaikan lagi tentang jawaban @Duncan dan jawaban lainnya berdasarkan elemen clearfix. Jika Anda ingin membuat konten dapat diklik, Anda memerlukan filez-index > 0 di atasnya atau clearfix akan menimpa konten dan menangani klik.

Ini adalah contoh yang tidak berfungsi (Anda tidak dapat melihat penunjuk kursor dan mengklik tidak akan melakukan apa-apa):

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

Meskipun ini yang sudah diperbaiki :

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

Saya telah menambahkan z-index: 1agar konten meningkatkan clearfix dan saya telah menghapus div kontainer menggunakan ng-repeat-startdanng-repeat-end (tersedia dari AngularJS 1.2) karena itu membuat z-index tidak berfungsi.

Semoga ini membantu!

Memperbarui

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


Apakah ini berfungsi dengan flexdalam baris untuk membuat kolom memiliki ketinggian yang sama?
Alisson

Saya tidak yakin saya mengerti pertanyaan Anda. Ini adalah plunker cepat untuk menunjukkan kepada Anda apa yang dilakukan kode ini: plnkr.co/edit/4w5wZj?p=preview . Dengan kata lain, clearfix dengan benar menyelaraskan baris kedua dari judul: semuanya dimulai dari titik yang sama tetapi masih tidak memiliki ketinggian yang sama (seperti yang Anda lihat berkat warna latar belakang). Coba hapus kelas clearfix untuk melihat apa yang merupakan perilaku default. Saya telah menggunakan flexbox hanya satu atau dua kali tetapi memiliki banyak properti css dan saya yakin Anda dapat menemukan apa yang Anda cari.
McGiogen

bootstrap memberikan contoh bagaimana membuat semua kolom dalam baris yang sama untuk mendapatkan ketinggian yang sama dari kolom tertinggi. Saya harus menggunakan ini. Masalahnya adalah kehilangan kemampuan untuk membungkus ke baris baru ketika ada lebih dari 12 kolom, jadi Anda perlu membuat baris baru secara manual. Setelah meneliti lebih lanjut, saya bisa mendapatkan solusi dan diposting di sini sebagai jawaban, meskipun saya tidak tahu apakah itu yang terbaik. Terima kasih, jawaban Anda membantu saya!
Alisson

Ini adalah pertama kalinya saya melihat contoh itu, ini sangat berguna! Senang bisa membantu Anda.
McGiogen

4

saya menyelesaikan ini menggunakan 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

Cara terbaik untuk menerapkan kelas adalah dengan menggunakan ng-class. Ini dapat digunakan untuk menerapkan kelas berdasarkan beberapa kondisi.

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

dan kemudian di pengontrol Anda

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

2

Setelah menggabungkan banyak jawaban dan saran di sini, ini adalah jawaban akhir saya, yang berfungsi dengan baik flex, yang memungkinkan kita membuat kolom dengan tinggi yang sama, juga memeriksa indeks terakhir, dan Anda tidak perlu mengulang HTML bagian dalam. Itu tidak menggunakan 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>

Ini akan menghasilkan sesuatu seperti ini:

<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

Sedikit modifikasi pada solusi @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.dll


0

Ini berhasil untuk saya, tidak perlu penyambungan atau apa pun:

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

Solusi Lahir yang terbaik, hanya perlu sedikit menyesuaikan kebutuhan, saya memiliki solusi responsif yang berbeda dan sedikit berubah

<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

Berdasarkan jawaban Alpar, berikut adalah cara yang lebih umum untuk membagi satu daftar item menjadi beberapa wadah (baris, kolom, ember, apa pun):

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

untuk daftar 10 item, menghasilkan:

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

Jumlah kontainer dapat dengan cepat dikodekan menjadi fungsi pengontrol:

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

Pendekatan ini menghindari duplikasi markup item ( <span>{{item.name}}</span>dalam hal ini) di template sumber - bukan kemenangan besar untuk rentang sederhana, tetapi untuk struktur DOM yang lebih kompleks (yang saya miliki) ini membantu menjaga template KERING.


0

Perbarui 2019 - Bootstrap 4

Karena Bootstrap 3 menggunakan float, diperlukan clearfix mengatur ulang setiap n (3 atau 4) kolom ( .col-*) .rowuntuk mencegah pembungkusan kolom yang tidak rata.

Sekarang Bootstrap 4 menggunakan flexbox , tidak perlu lagi membungkus kolom dalam .rowtag terpisah , atau untuk memasukkan div tambahan untuk memaksa kolom membungkus setiap n. kolom.

Anda cukup mengulangi semua kolom dalam satu .rowwadah.

Misalnya 3 kolom di setiap baris visual adalah:

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

Jadi untuk Bootstrap ng-repeat cukup:

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

Demo: https://www.codeply.com/go/Z3IjLRsJXX


0

Saya melakukannya hanya dengan boostrap, Anda harus sangat berhati-hati di lokasi baris dan kolom, ini contoh saya.

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.