AngularJS ng-repeat tanpa elemen html

91

Saat ini saya menggunakan potongan kode ini untuk membuat daftar:

<ul ng-cloak>
    <div ng-repeat="n in list">
        <li><a href="{{ n[1] }}">{{ n[0] }}</a></li>
        <li class="divider"></i>
    </div>
    <li>Additional item</li> 
</ul>

Namun, <div>elemen tersebut menyebabkan beberapa cacat rendering yang sangat kecil pada beberapa browser. Saya ingin tahu apakah ada cara untuk melakukan ng-repeat tanpa wadah div, atau beberapa metode alternatif untuk mencapai efek yang sama.

nehz
sumber
Masalah rendering apa yang Anda bicarakan?
Ja͢ck
pembatas li terakhir sepertinya sedikit lebih tebal seperti yang ditumpuk (chrome win7). Ini bisa menjadi masalah css, namun, saya ingin tahu apakah ini bisa diperbaiki secara bersudut. Sebagai perbandingan, knockoutJS memungkinkan binding tanpa kontainer menggunakan <! - ->.
nehz
Begitu, saya menggunakan phptal di sisi server dan mereka memiliki tag tal: block khusus untuk tujuan ini :) tebak dengan DOM tidak selalu menerima jenis tag baru yang lebih sulit dengan sudut
Ja͢ck
Bisakah Anda juga memperbarui html untuk mencerminkan bagaimana Anda menggunakan htmlAppenddirektif?
Nick
Selesai ... melakukan ini beberapa waktu yang lalu, tapi saya ingat itu berhasil
nehz

Jawaban:

104

Seperti yang dikatakan Andy Joslin bahwa mereka sedang mengerjakan pengulangan ng berbasis komentar tetapi tampaknya ada terlalu banyak masalah browser . Untungnya AngularJS 1.2 menambahkan dukungan bawaan untuk pengulangan tanpa menambahkan elemen turunan dengan direktif baru ng-repeat-startdan ng-repeat-end.

Berikut adalah contoh kecil untuk menambahkan pagination Bootstrap :

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>
  <li ng-repeat-start="page in [1,2,3,4,5,6]"><a href="#">{{page}}</a></li>
  <li ng-repeat-end class="divider"></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

Contoh kerja lengkap dapat ditemukan di sini .

John Lindquist juga memiliki video tutorial tentang ini di halaman egghead.io-nya yang sangat bagus .

jmagnusson.dll
sumber
3
Bukankah ini membutuhkan cetakan elemen?
hitautodestruct
2
Saya benar-benar bingung apa yang dicapai hanya dengan <li ng-repeat = "halaman di [1,2,3,4,5,6]"> <a href="#"> {{halaman}} </ a > </li> -edit: tidak apa-apa, saya pikir saya mengerti
Shadaez
6
Saya mengerti bahwa Anda hanya mencoba untuk mendemonstrasikan ng-repeat-start/endtetapi ini adalah contoh yang membingungkan dan kasus penggunaan yang salah untuk itu. Standar ng-repeatharus digunakan di sini karena kode Anda membuat kosong ekstra liuntuk setiap item. Anda mungkin harus menyebutkannya di posting Anda.
GFoley83
2
@ GFoley83 Anda benar. Tetapi dia tampaknya menginginkan elemen ekstra itu untuk setiap iterasi, sesuatu yang tidak mungkin tanpanya ng-repeat-start. Saya akan menambahkan dividerkelas html ke jawaban saya agar lebih jelas.
jmagnusson
1
ng-repeat-startdan ng-repeat-endsedikit membingungkan. Dokumentasi Angular membantu: https://docs.angularjs.org/api/ng/directive/ngRepeat#special-repeat-start-and-end-points
perilandmishap
30

KnockoutJS sintaks pengikat tanpa kontainer

Harap bersabar sebentar: KnockoutJS menawarkan opsi yang sangat nyaman untuk menggunakan sintaks pengikat tanpa kontainer untuk foreachpengikatannya seperti yang dibahas dalam Catatan 4 dari foreachdokumentasi penjilidan. http://knockoutjs.com/documentation/foreach-binding.html

Seperti yang diilustrasikan oleh contoh dokumentasi Knockout, Anda dapat menulis binding Anda di KnockoutJS seperti ini:

<ul>
    <li class="header">Header item</li>
    <!-- ko foreach: myItems -->
        <li>Item <span data-bind="text: $data"></span></li>
    <!-- /ko -->
</ul>

Saya rasa cukup disayangkan AngularJS tidak menawarkan jenis sintaks ini.


Angular ng-repeat-startdanng-repeat-end

Dalam cara AngularJS untuk memecahkan ng-repeatmasalah, sampel yang saya temukan adalah tipe jmagnusson yang diposting dalam jawabannya (membantu).

<li ng-repeat-start="page in [1,2,3,4,5]"><a href="#">{{page}}</a></li>
<li ng-repeat-end></li>

Pikiran asli saya setelah melihat sintaks ini adalah: benarkah? Mengapa Angular memaksakan semua markup ekstra yang tidak ingin saya lakukan dan itu jauh lebih mudah di Knockout? Tapi kemudian komentar hitautodestruct dalam jawaban jmagnusson mulai membuat saya bertanya-tanya: apa yang dihasilkan dengan ng-repeat-start dan ng-repeat-end pada tag terpisah?


Cara yang lebih bersih untuk menggunakan ng-repeat-startdanng-repeat-end

Setelah menyelidiki pernyataan hitautodestruct, menambahkan ng-repeat-endke tag terpisah persis seperti yang tidak ingin saya lakukan dalam banyak kasus, karena menghasilkan elemen yang sama sekali tidak berguna: dalam hal ini, <li>item yang tidak memiliki apa pun di dalamnya. Daftar paginasi Bootstrap 3 mengatur gaya item daftar sehingga terlihat seperti Anda tidak menghasilkan item yang berlebihan, tetapi ketika Anda memeriksa html yang dihasilkan, mereka ada di sana.

Untungnya , Anda tidak perlu melakukan banyak hal untuk mendapatkan solusi yang lebih bersih dan jumlah html yang lebih pendek: cukup letakkan ng-repeat-enddeklarasi di tag html yang sama yang memiliki ekstensing-repeat-start .

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>    
  <li ng-repeat-start="page in [1,2,3,4,5]" ng-repeat-end><a href="#"></a></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

Ini memberikan 3 keuntungan:

  1. lebih sedikit tag html untuk ditulis
  2. tidak berguna, tag kosong tidak dibuat oleh Angular
  3. ketika larik yang akan diulang kosong, tag dengan ng-repeattidak akan dibuat, memberi Anda keuntungan yang sama dengan pengikatan tanpa kontainer Knockout yang memberi Anda dalam hal ini

Tapi masih ada cara yang lebih bersih

Setelah meninjau lebih lanjut komentar di github tentang masalah ini untuk Angular, https://github.com/angular/angular.js/issues/1891 ,
Anda tidak perlu menggunakan ng-repeat-startdan ng-repeat-endmendapatkan keuntungan yang sama. Sebagai gantinya, bercabang lagi contoh jmagnusson, kita bisa pergi:

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>
  <li ng-repeat="page in [1,2,3,4,5,6]"><a href="#">{{page}}</a></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

Jadi kapan harus digunakan ng-repeat-startdan ng-repeat-end? Sesuai dokumentasi sudut , untuk

... ulangi serangkaian elemen, bukan hanya satu elemen induk ...

Cukup bicara, tunjukkan beberapa contoh!

Cukup adil; jsbin ini menjelaskan lima contoh tentang apa yang terjadi saat Anda melakukannya dan saat Anda tidak menggunakan ng-repeat-endtag yang sama.

http://jsbin.com/eXaPibI/1/

mg1075
sumber
11
Anda tampaknya telah salah memahami maksud pertanyaan tersebut. Sasarannya adalah mengulangi dua item daftar atau lebih secara bersamaan, dan baik contoh Anda maupun halaman yang Anda tautkan tidak menyediakan cara untuk melakukannya. Seperti yang Anda catat sendiri, melampirkan ng-repeat-startdan ng-repeat-endke elemen yang sama sama sekali tidak berguna ketika Anda dapat menggunakan default angular ng-repeatdan selesai dengannya.
Asad Saeeduddin
@ Asad - "intinya" tidak dinyatakan dengan jelas oleh OP. Selain itu, sudahkah Anda memeriksa keluaran DOM yang dirender dari jawaban yang diterima? Saya tidak bisa membayangkan ada orang yang menginginkan output semacam itu, setidaknya pasti bukan untuk daftar pagination bootstrap.
mg1075
1
@ mg1075 Ya, keluaran dari jawaban yang diterima tidak dapat diterima, itulah sebabnya saya menggulir ke bawah sini. Inti dari pertanyaannya sangat jelas: temukan cara untuk menerapkan ng-repeatatau mencari alternatif penggunaan OP ng-repeatyang menghilangkan divartefak di HTML. Jawaban Anda tidak melakukan ini, karena tidak ada cara untuk menggunakannya untuk dua lielemen dalam pertanyaan. Jika saya salah di sini, berikan contoh markup yang menyesuaikan kode OP untuk menghilangkan divelemen.
Asad Saeeduddin
@ Asad - Inti pertanyaannya akan lebih jelas jika OP telah memberikan contoh hasil akhir yang dia inginkan. Fakta bahwa dia menerima jawaban yang "diterima", di mana jawaban yang diterima menggunakan pagination bootstrap dengan markup yang pada dasarnya tidak tepat, hanya semakin memperjelas masalah. Contoh 2 di jsbin, jika itu yang benar-benar dimaksudkan, memecahkan masalah OP dengan cara yang dilakukan oleh jawaban yang diterima, tetapi tidak ada yang boleh menggunakan jenis markup tersebut untuk paginasi bootstrap. jsbin.com/eXaPibI/1
mg1075
1
Sebenarnya saya baru melihat kembali jawaban pertama dan markup yang dihasilkan benar-benar tepat untuk use case OP, padahal tidak memenuhi kebutuhan saya. OP menginginkan liitem pembagi dibuat, yang merupakan ekstra yang liAnda lihat di jsbin Anda.
Asad Saeeduddin
6

ngRepeat mungkin tidak cukup, namun Anda dapat menggabungkannya dengan perintah kustom. Anda dapat mendelegasikan tugas untuk menambahkan item pembagi ke kode jika Anda tidak keberatan dengan jQuery.

 <li ng-repeat="item in coll" so-add-divide="your exp here"></li>

Direktif sederhana seperti itu tidak benar-benar membutuhkan nilai atribut tetapi mungkin memberi Anda banyak kemungkinan seperti menambahkan pembagi secara kondisional sesuai dengan indeks, panjang, dll atau sesuatu yang sama sekali berbeda.

orcun
sumber
2
keren, saya menambahkan arahan khusus dan berhasil. Panduan video ini membantu: youtube.com/watch?v=A6wq16Ow5Ec
nehz
3

Saya baru-baru ini mengalami masalah yang sama yaitu saya harus mengulangi koleksi span dan gambar yang sewenang-wenang - memiliki elemen di sekitarnya bukanlah pilihan - namun ada solusi sederhana, buat petunjuk "null":

app.directive("diNull", function() {
        return {
            restrict: "E",
            replace: true,
            template: ""
        };
    });

Anda kemudian dapat menggunakan pengulangan pada Elemen itu, di mana elemen.url menunjuk ke templat untuk elemen itu:

<di-null ng-repeat="element in elements" ng-include="element.url" ></di-null>

Ini akan mengulangi sejumlah templat berbeda tanpa wadah di sekitarnya

Catatan: hmm saya berani bersumpah ini menghapus elemen di-null saat rendering, tetapi memeriksanya lagi itu tidak ... masih menyelesaikan masalah tata letak saya ... lebih aneh dan lebih penasaran ...

Raphael Huerzeler
sumber
replacetidak digunakan lagi sejak 2.0.
demalexx
Saya mencoba cara di atas, tetapi template: "" menyebabkan tidak ada yang berubah. Saya menggunakan linker dari jsfiddle.net/markcoleman/fMP9s/1 dan memodifikasinya: link: function (scope, element, attrs) {element [0] .outerHTML = ''; $ compile (element.contents ()) (scope); }
Lauri Lubi
1

Ada batasan perintah komentar, tetapi ngRepeat tidak mendukungnya (karena memerlukan elemen untuk diulang).

Saya rasa saya melihat tim sudut mengatakan mereka akan mengerjakan pengulangan komentar, tapi saya tidak yakin. Anda harus membuka masalah untuk itu di repo. http://github.com/angular/angular.js

Andrew Joslin
sumber
Komentar dari 2012. Apakah masih demikian? Mencoba mencari di dokumentasi mereka, dan tidak dapat menemukan referensi apapun.
Zack S
1

Tidak ada cara ajaib Angular untuk melakukan ini, untuk kasus Anda, Anda dapat melakukan ini, untuk mendapatkan HTML yang valid, jika Anda menggunakan Bootstrap. Kemudian Anda akan mendapatkan efek yang sama seperti menambahkan li.divider

Buat kelas:

span.divider {
 display: block;
}

Sekarang ubah kode Anda menjadi ini:

<ul ng-cloak>
 <li div ng-repeat="n in list">
    <a href="{{ n[1] }}">{{ n[0] }}</a>
    <span class="divider"></span>
 </li>
 <li>Additional item</li>
</ul>
Eduardo di Norwegia
sumber
1

untuk solusi yang benar-benar berhasil

html

<remove  ng-repeat-start="itemGroup in Groups" ></remove>
   html stuff in here including inner repeating loops if you want
<remove  ng-repeat-end></remove>

tambahkan direktif angular.js

//remove directive
(function(){
    var remove = function(){

        return {    
            restrict: "E",
            replace: true,
            link: function(scope, element, attrs, controller){
                element.replaceWith('<!--removed element-->');
            }
        };

    };
    var module = angular.module("app" );
    module.directive('remove', [remove]);
}());

untuk penjelasan singkat,

ng-repeat mengikat dirinya sendiri ke <remove>elemen dan melakukan loop sebagaimana mestinya, dan karena kami telah menggunakan ng-repeat-start / ng-repeat-end, ia akan memutar blok html bukan hanya sebuah elemen.

lalu perintah hapus khusus menempatkan elemen <remove>awal dan akhir dengan<!--removed element-->

Clint
sumber
Ini menarik. Namun, dalam pengujian saya replaceWith(...)menghasilkan node teks bukan komentar. Saya telah menemukan hanya menggunakan element.remove()karya.
artfulrobot