Bir html öğesi olmadan ng-repeat nasıl kullanılır


142

ng-repeatBir dizideki tüm öğeleri listelemek için (AngularJS içinde) kullanmanız gerekir .

Komplikasyon, dizinin her elemanının bir tablonun bir, iki veya üç satırına dönüşmesidir.

Eğer geçerli html yaratamazsınız ng-repeatbir elemanda kullanılan yinelenen elemanın hiçbir tür arasında izin olduğunda, <tbody>ve <tr>.

Örneğin, ng-repeat'ı kullansaydım <span>şunları elde ederim:

<table>
  <tbody>
    <span>
      <tr>...</tr>
    </span>
    <span>
      <tr>...</tr>
      <tr>...</tr>
      <tr>...</tr>
    </span>
    <span>
      <tr>...</tr>
      <tr>...</tr>
    </span>
  </tbody>
</table>          

Hangi geçersiz html.

Ama üretilmesi gereken şey:

<table>
  <tbody>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
  </tbody>
</table>          

burada ilk satır ilk dizi elemanı tarafından, sonraki üçü ikinci ve beşinci ve altıncı sırada son dizi elemanı tarafından oluşturulur.

Ng-repeat'i, bağlı olduğu html öğesinin oluşturma sırasında kaybolacağı şekilde nasıl kullanabilirim?

Yoksa bunun başka bir çözümü var mı?


Açıklama: Oluşturulan yapı aşağıdaki gibi görünmelidir. Her dizi elemanı tablonun 1-3 satırı arasında üretilebilir. Yanıt ideal olarak dizi öğesi başına 0-n satırı desteklemelidir.

<table>
  <tbody>
    <!-- array element 0 -->
    <tr>
      <td>One row item</td>
    </tr>
    <!-- array element 1 -->
    <tr>
      <td>Three row item</td>
    </tr>
    <tr>
      <td>Some product details</td>
    </tr>
    <tr>
      <td>Customer ratings</td>
    </tr>
    <!-- array element 2 -->
    <tr>
      <td>Two row item</td>
    </tr>
    <tr>
      <td>Full description</td>
    </tr>
  </tbody>
</table>          

Belki de "replace: true" kullanmalısınız?

Ayrıca, neden tr tekrarında ng-repeat kullanmıyorsunuz?

2
@Tommy, çünkü "dizinin her öğesi bir tablonun bir, iki veya üç satırına dönüşecektir". Eğer ng-tekrar kullandıysam tranladığım kadarıyla dizi elemanı başına bir satır alırdım.
fadedbee

1
Tamam anladım. Tekrarlayıcıda kullanmadan önce modeli düzleştiremez misiniz?

@Tommy, hayır. trBir dizi elemanı tarafından üretilen 1-3 sn'ler aynı yapıya sahip değildir.
Fadedbee

Yanıtlar:


66

Güncelleme: Açısal 1.2+ kullanıyorsanız, ng-repeat-start kullanın . @ Jmagnusson'un cevabına bakınız.

Aksi takdirde, t-tekrarı tekrar takmaya ne dersiniz? (AFAIK, tek bir tabloda birden fazla <tbody> bulunması iyidir.)

<tbody ng-repeat="row in array">
  <tr ng-repeat="item in row">
     <td>{{item}}</td>
  </tr>
</tbody>

62
Bu teknik olarak işe yarayabilir olsa da, bu yaygın kullanım durumu için cevabın keyfi (aksi takdirde gereksiz) işaretleme yapmanız gerektiğidir. Ben aynı sorun var (tekrarlanan satır grupları - bir üstbilgi TR bir veya daha fazla alt TR, bir grup olarak tekrarlanan). Diğer şablon motorları ile önemsiz, en iyi Angular ile hacky gibi görünüyor.
Brian Moeskau

1
Kabul. DT + DD öğelerinde bir tekrar yapmaya çalışıyorum. geçersiz bir sarma öğesi eklemeden bunu yapmanın bir yolu yok
David Lin

2
@DavidLin, Angular v1.2'de (her ne zaman ortaya çıkarsa), dt ve dd gibi birden çok öğeyi tekrarlayabilirsiniz: youtube.com/watch?v=W13qDdJDHp8&t=17m28s
Mark Rajcok

Bu, KnockoutJS'de kapsayıcı kontrol akışı sözdizimi kullanılarak zarif bir şekilde ele alınır: knockoutjs.com/documentation/foreach-binding.html . Angular'ın yakında benzer bir şey yaptığını görmeyi umuyoruz.
Cory House

3
Bu cevap modası geçmiş, bunun yerine ng-repeat-start kullanın
51 iwein

73

AngularJS 1.2'den itibaren ng-repeat-starttam olarak istediğinizi yapan bir direktif var . Nasıl kullanılacağına ilişkin bir açıklama için bu sorudaki cevabıma bakın .


Açısal yakalandı, şimdi doğru çözüm bu.
Iwein

33

Ng> 1.2 kullanıyorsanız ng-repeat-start/end, gereksiz etiketler oluşturmadan kullanma örneği :

<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script>
      angular.module('mApp', []);
    </script>
  </head>
  <body ng-app="mApp">
    <table border="1" width="100%">
      <tr ng-if="0" ng-repeat-start="elem in [{k: 'A', v: ['a1','a2']}, {k: 'B', v: ['b1']}, {k: 'C', v: ['c1','c2','c3']}]"></tr>

      <tr>
        <td rowspan="{{elem.v.length}}">{{elem.k}}</td>
        <td>{{elem.v[0]}}</td>
      </tr>
      <tr ng-repeat="v in elem.v" ng-if="!$first">
        <td>{{v}}</td>
      </tr>

      <tr ng-if="0" ng-repeat-end></tr>
    </table>
  </body>
</html>

Önemli nokta: Sayfada eklenmemesi için kullanılan ng-repeat-startve ng-repeat-endayarlanan etiketler için ng-if="0". Bu şekilde iç içerik tam olarak knockoutjs'de olduğu gibi (komutları kullanarak <!--...-->) ele alınacak ve çöp olmayacaktır.


ng-if = "0" ayarlandıktan sonra, eşleşen ng-tekrar sonu bulunamıyor diyerek hata veriyor.
vikky MCTS

19

Denetleyicinizdeki verileri düzleştirmek isteyebilirsiniz:

function MyCtrl ($scope) {
  $scope.myData = [[1,2,3], [4,5,6], [7,8,9]];
  $scope.flattened = function () {
    var flat = [];
    $scope.myData.forEach(function (item) {
      flat.concat(item);
    }
    return flat;
  }
}

Ve sonra HTML'de:

<table>
  <tbody>
    <tr ng-repeat="item in flattened()"><td>{{item}}</td></tr>
  </tbody>
</table>

1
Hayır değil. NgRepeat ifadesinin içindeki bir işlevi çağırmak kesinlikle önerilmez
Nik

! Benim durumumda, ben her bir elemanın indeksi için bir ayırıcı eklemeniz = 0 ihtiyaç ve yoktu ng-repeat-start, ng-repeat-endçözüm yinelemek yeni var her öğe önce bu ayırıcı nesnesini ekleyerek fazladan değişken oluşturmak için ve böylece, benim tasarım kırmak: <div class="c477_group"> <div class="c477_group_item" ng-repeat="item in itemsWithSeparator" ng-switch="item.id" ng-class="{'-divider' : item.id == 'SEPARATOR'}"> <div class="c478" ng-switch-when="FAS"/> <div class="c478" ng-switch-when="SEPARATOR" /> <div class="c479" ng-switch-default /> </div> </div>
hermeslm

6

Yukarıdakiler doğrudur, ancak daha genel bir cevap için yeterli değildir. Ben ng-tekrar yuva gerekiyordu, ama aynı html düzeyinde kalmak, yani aynı ebeveyn öğeleri yazmak anlamına gelir. Tags dizisi, aynı zamanda bir etiket dizisine de sahip olan etiketler içerir. Aslında bir ağaç.

[{ name:'name1', tags: [
  { name: 'name1_1', tags: []},
  { name: 'name1_2', tags: []}
  ]},
 { name:'name2', tags: [
  { name: 'name2_1', tags: []},
  { name: 'name2_2', tags: []}
  ]}
]

İşte sonunda yaptıklarım.

<div ng-repeat-start="tag1 in tags" ng-if="false"></div>
    {{tag1}},
  <div ng-repeat-start="tag2 in tag1.tags" ng-if="false"></div>
    {{tag2}},
  <div ng-repeat-end ng-if="false"></div>
<div ng-repeat-end ng-if="false"></div>

Başlangıç ​​ve bitiş bölümlerini gizleyen ng-if = "false" değerine dikkat edin.

Yazdırmalı

isim1, name1_1, name1_2, isim2, name2_1, name2_2,


1

Sadece yorum yapmak istiyorum ama itibarım hala eksik. Bu yüzden sorunu da çözen başka bir çözüm ekliyorum. @Bmoeskau tarafından yapılan bu sorunun çözülmesinin 'en iyi hacky' çözümü gerektirdiğini açıklamaktan gerçekten vazgeçmek istiyorum ve bu yazı 2 yaşında olmasına rağmen son zamanlarda bir tartışmada ortaya çıktığı için, iki sente sahip:

@Btford'un işaret ettiği gibi, özyinelemeli bir yapıyı bir listeye dönüştürmeye çalışıyorsunuz, bu yüzden önce bu yapıyı bir listeye düzleştirmelisiniz. Onun çözümü bunu yapar, ancak şablonun içindeki işlevi çağırmanın yetersiz olduğu yönünde bir görüş vardır. bu doğruysa (dürüst olmak gerekirse, bilmiyorum) sadece yönerge yerine denetleyicide işlev yürütülmesi gerekmez mi?

her iki durumda da, html'niz bir liste gerektirir, bu nedenle onu oluşturan kapsamın birlikte çalışması için bu listeye sahip olması gerekir. kontrolörünüzün içindeki yapıyı düzleştirmeniz yeterlidir. $ scope.rows dizisine sahip olduğunuzda, tabloyu tek bir basit ng-yineleme ile oluşturabilirsiniz. Saldırı yok, beceriksizlik yok, sadece çalışmak için tasarlandığı şekilde.

Açısal yönergelerin işlevselliği yoktur. Sadece geçerli html yazmaya zorlarlar. Bir meslektaşımın benzer bir sorunu vardı, @bmoeskau'ya açısal şablonlar oluşturma / oluşturma özellikleriyle ilgili eleştirileri desteklemek için. Kesin soruna baktığımızda, sadece bir açık etiket, daha sonra başka bir yerde yakın bir etiket, vb .. oluşturmak istediğimiz ortaya çıktı. Hayır.

yapıyı bir liste halinde düzleştirmeye gelince, işte başka bir çözüm:

// assume the following structure
var structure = [
    {
        name: 'item1', subitems: [
            {
                name: 'item2', subitems: [
                ],
            }
        ],
    }
];
var flattened = structure.reduce((function(prop,resultprop){
    var f = function(p,c,i,a){
        p.push(c[resultprop]);
        if (c[prop] && c[prop].length > 0 )
          p = c[prop].reduce(f,p);
        return p;
    }
    return f;
})('subitems','name'),[]);

// flattened now is a list: ['item1', 'item2']

bu, alt öğeleri olan herhangi bir ağaç benzeri yapı için işe yarayacaktır. Bir özellik yerine tüm öğeyi istiyorsanız, düzleştirme işlevini daha da kısaltabilirsiniz.

umarım yardımcı olur.


Güzel bir. Bana doğrudan yardımcı olmasa da aklımı başka bir çözüme açtı. Çok teşekkürler!
Marian Zburlea

0

gerçekten işe yarayan bir çözüm için

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>

angular.js yönergesi ekle

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

kısa bir açıklama için,

ng-repeat kendisini <remove>elemente bağlar ve olması gerektiği gibi döngüler ve ng-repeat-start / ng-repeat-end kullandığımız için sadece bir eleman değil, bir html bloğu döngüler.

özel kaldırma yönergesi <remove>başlangıç ​​ve bitiş öğelerini<!--removed element-->


-2
<table>
  <tbody>
    <tr><td>{{data[0].foo}}</td></tr>
    <tr ng-repeat="d in data[1]"><td>{{d.bar}}</td></tr>
    <tr ng-repeat="d in data[2]"><td>{{d.lol}}</td></tr>
  </tbody>
</table>

Bunun geçerli olduğunu düşünüyorum :)


Bu çalışırken, yalnızca dizinin üç öğesi varsa çalışır.
btford

Dizinin boş diziler olsa bile 3 öğeye sahip olduğundan emin olun (boş bir diziyle ng-tekrarı hiçbir şey oluşturmaz).
Renan Tomal Fernandes

7
Demek istediğim, OP muhtemelen dizideki değişken sayıda öğe için çalışan bir çözüm istiyordu. Şablon içine "bu dizide üç öğe olmalı" sabit kodlama kötü bir çözüm olacağını varsayalım.
btford

Sorusuna ilişkin son yorumda, öğelerin aynı yapıya sahip olmayacağını, bu nedenle her yapının kodlanmasının kaçınılmaz olduğunu söylüyor.
Renan Tomal Fernandes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.